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

CODE

DARK PAPERS ON ZIM CODE!

ZIM CODE for JavaScript HTML Canvas Coding
SHOW
ORGANIZATION
HIDE
// ZIM is organized in sections:
// FRAME, DISPLAY, METHODS, CONTROLS, CODE, WRAP, META
// Let's have a brief look at each...
// see https://zimjs.com/docs.html all the details!

// NOTE: ZIM works fine with ES6 - these examples are in ES5 
// All CodePen examples at https://codepen.io/topic/zim for instance are ES6

// ---------------------------------
// FRAME - the framework class that makes and scales the canvas and stage
// scaling, width, height, color, outerColor, assets, path, etc.
const frame = new Frame("fit", 1024, 768, light, dark, ["pic.png", "sound.mp3"], "assets/");
frame.on("ready", () => {
    const stage = frame.stage;
    const pic = asset("pic.png").center();
    pic.on("click", () => {
        asset("sound.mp3").play();
    });    
    stage.update();
}); // end ready


// ---------------------------------
// DISPLAY - classes for objects viewed on the stage like shapes and components
const circle = new Circle(100, red); // also Rectangle, Triangle and Blob
const button = new Button(200, 100, "GO!");
// etc. and dozens more like Label, Slider, Dial, Tabs, ColorPicker...


// ---------------------------------
// METHODS - methods for the display objects above
circle.center(); // adds to and centers button on stage
circle.drag(); // allows the circle to be dragged and dropped
circle.animate(obj:{alpha:0}, 5); // fades out circle over 5 seconds
// etc. and dozens more - also see PRINCIPLES sections below...


// ---------------------------------
// CONTROLS - classes that affect Display objects
new MotionController(circle); // circle moves to mouse press
new Pages(stage, {page:home}, {page:help}); // handle pages and swiping
new Layout(stage, [{object:header},{object:content},{object:footer}]);
// responsive design with many more options (like css flex table)
// etc. including Parallax, Scroller, Pen, Guide, Grid, Emitter, SoundWave...


// ---------------------------------
// CODE - non-Canvas code convienence functions
const array = [red, yellow, green, blue];
let color = shuffle(array)[0]; // shuffles array and picks first color
// let color = array[rand(array.length-1)]; // gets random element
// etc. many more including browser functions and asynchronous calls


// ---------------------------------
// WRAP - a dozen three-letter global functions starting with z
zog("hello world"); // short for console.log();
zid("tagID"); // short for document.getElementById();
// etc. including selectors similar to $() in jQuery


// ---------------------------------
// META - a few classes and functions operating on zim
DISTILL = true;
distill(); // writes to console all the commands used to reduce code
zimify(createjsObj); // adds zim Methods to native createjs display objects
wonder.count("wow"); // once set up records different types of stats


// ---------------------------------
The docs have all the details and changes are found at
https://zimjs.com/updates.html
Please also see the TRICKS section below!

TREATS
HIDE

// Here are some handy things that ZIM provides to make coding easier
// In the later examples, we list a few handy things CreateJS and JavaScript provide


// ---------------------------------
// CONFIGURATION OBJECTS
// Introduced in ZIM DUO so referred to as the ZIM DUO technique

// Classes, methods and functions accept parameters (often dozens)
// These are values only and the order matches an expected order as defined in the docs
// Many parameters have default values but order must be kept
// So if you want to only set the seventh parameter to false then you need six placeholder null values
circle.drag(null, null, null, null, null, null, false);

// This is really unmanageable at times so ZIM also accepts a configuration object as a single parameter
// The configuration object has properties that match the parameter names as set out in the docs
// The order in which we provide the properties does not matter:
circle.drag({onTop:false});
circle.drag({onTop:false, slide:true});

// Note: when there are only a few parameters, the ZIM DUO technique might not be available (see docs)
// Note: this is an alternative to having a short list of parameters and then setting properties after
// Advanced note: this technique is accomplished with zob() and you can use it in your own code


// ---------------------------------
// CHAINING
// Chainable methods let you place one method after the other in the same statement
// It is a technique to avoid repeating the object
// Traditionally we would have multiple statements - and these still work:
const circle = new Circle();
circle.center();
circle.x -= 100; // move it to the left
circle.drag();

// Chainable methods return the object they are placed on
// Below, the Circle object is created and then centered
// the center() method returns the Circle object which then has its drag() set
// the drag() method returns the Circle object which is then assigned to the const circle
const circle = new Circle().center().mov(-100).drag();

// Often we stack the methods (this allows us to comment out parts too)
// Note: watch you only put the semi-colon on your last line
const circle = new Circle()
    .center()
    .mov(-100)
    .drag();

// You cannot assign an object to a variable if you chain a property on the end:
const circle = new Circle().center().alpha = .5; // would put .5 into const circle

// So ZIM provides a set of short chainable methods (like mov() in the example above):
loc(x, y, container)
pos(x, y, right, bottom, container)
mov(relativeX, relativeY)
alp(alpha)
rot(rotation)
siz(width, height, only)
ske(skewX, skewY)
reg(regX, regY)
sca(scale, scaleY)


// ---------------------------------
// STYLE
// STYLE can be used to set any parameter on a DisplayObject.
// For instance: Circle, Blob, Button, Pane, Bitmap, Sprite, etc.
// These are applied at the time the objects are made.
// They are cascading with each level overriding the previous level:
//
// 1. GENERAL: any style can be specified in general
//    corner:30 will make all corners default to 30
// 2. TYPE: styles for object type can be set to override the general styles
//    Button:{corner:0} will make all button corners default to 0
// 3. GROUP: styles for a group can be set to override the type styles
//    homePage:{corner:20} will make all objects of that group default to 20
// 4. OBJECT: styles applied as parameters to the object override all other styles
//    new Button({corner:40}) will make this button have a corner of 40

STYLE = {
   corner:20,
   backgroundColor:pink,
   type:{
      Button:{width:{min:100, max:500}, corner:0, centerReg:true, move:{y:series([-150, -50, 50, 150])}},
      Dial:{add:true, x:800, y:600, backgroundColor:red, scale:2, outline:true},
      Pane:{corner:ignore, color:white, draggable:true, width:300, label:"HI!"},
      ProgressBar:{add:true, x:200, y:600, barType:"rectangle", transform:true},
      Tabs:{add:true, x:100, y:100}
   },
   group:{
      homePage:{corner:30}
   }
}
new Button(); // will have a corner of 0 and be pink
new Button({group:"homePage"}); // will have a corner of 30 and be pink
new Button({corner:10, group:"homePage"}); // will have a corner of 10 and be pink
new Button({corner:"ignore"}) // will have a corner of its default 20 and be pink
new Button({style:false}).pos(700,100); // will have original default styles
new Dial(); // will be red and scaled twice as big and have an outline
new Tabs(); // will have a corner of 20 and selection will be pink
var p = new ProgressBar({corner:15}); // will be a bar with transform tools, corner 15
p.percent = 25;
new Pane().show(); // will ignore corner 30 and use its original 20 - it will say HI! in white and be draggable

STYLE can now accept the DisplayObject class names directly:

STYLE = {Button:{backgroundColor:red}}; // no need for type:{Button:{etc.}}


// ---------------------------------
// LOOPS
// A traditional for loop in JavaScript looks like this:
for (let i=0; i<10, i++) {
    zog(i);
}

// ZIM provides a simpler and more feature rich loop:
loop(10, i => {
    zog(i);
});

// often we loop through an array, an object or a zim Container
// ZIM loop provides an additional context sensitive first parameter:
const array = [red, green, yellow, blue];
loop(array, color => { // the index number is now the second parameter
    zog(color);
});

// Note: to continue in a loop use return - to exit the loop return a value
// See the docs for more features and examples (note, there are TWO listings for ZIM loop)


// ---------------------------------
// TIMEOUT AND INTERVAL
// As of ZIM Cat, time is in seconds rather than milliseconds (see TIME constant to adjust)
// A traditional time out and interval in JavaScript looks like this:
setTimeout(()=>{zog("once after a second");}, 1000);
setInterval(()=>{zog("repeat after a second");}, 1000);

// These do not use a requestAnimationFrame so they can take resources when app is minimized
// and contrary to event listener format, the function comes first which obscures the time
// ZIM provides a timeout and interval to adjust these and adds more features
// such as a total number for the interval, run immediately, pause(), time, count, etc. see docs
timeout(1, ()=>{zog("once after a second"););
interval(1, ()=>{zog("repeat after a second"););


// ---------------------------------
// ZIM VEE VALUE
// Introduced in ZIM VEE (5) as a way to pass in dynamic parameters
// For instance, ZIM Emitter emits particles and we may want to emit a variety of particles
// We might want to pass in a range of decay times, etc.
// We could pass in a random number for the decay time but then it would always use that decay time
// So, a global function called zik() was created to PICK from a ZIM VEE value

// The ZIM VEE value can be the following:
// 1. an Array of values to pick from - eg. [red, green, blue]
// 2. a series - eg. series(red, green, blue) to run in order
// 3. a Function that returns a value - eg. function(){return Date.now();}
// 4. a ZIM RAND object literal - eg. {min:10, max:20, integer:true, negative:true} max is required
// 5. any combination of the above - eg. [red, function(){x>100?[green, blue]:yellow}] zik is recursive
// 6. a single value such as a Number, String, Rectangle(), etc. this just passes through unchanged
// The docs will indicate when a ZIM VEE value can be used as a parameter

// For instance, here is a ZIM interval that changes the interval time as it runs:
interval({min:.2, max:.8}, dropBombs); // bombs will fall at different rates between .2s and .8s
interval([1, 2], dropBombs); // bombs will fall at either 1 or 2 s


// ---------------------------------
// EXTENDING ZIM
// Of course, the many treats of ZIM are really the DISPLAY classes, METHODS and CONTROLS
// The DISPLAY classes extend CreateJS classes (see the CreateJS panel below)
// And you can extend the ZIM classes in a similar way with extend()
// This is a helper method that wraps up the tricky JavaScript 5 process of extending classes
// extend() is based on the CreateJS extend() method with a few changes:
var Collection = function() {
   // the super constructor must be run
   this.super_constructor();
   // custom properties and methods, etc.
}
extend(Collection, Container); // Collection will be a Container
// see the docs for more options

// In ES6 this is:
class Collection extends Container {
    constructor() {
        super();
        // etc.       
   }
}

// ---------------------------------
// JAVASCRIPT FUNCTIONS
// In JavaScript we can define (declare) and call (run) a function like so:
function greet() {zog("hello");}
greet();

// In JavaScript, a function is also first-class object
// So we can store a function object in a variable (just like storing a Number object in a variable):
const greet = function(){zog("hello");}; // a function literal or an anonymous function assigned to a const
greet(); // run the function - will log "hello" in the console

// We also have a new Arrow function in ES6 
button.on("click", ()=>{});
// same as anonymous
button.on("click", function(){}); // in ES5
// or a named function 
button.on("click", go); 
function go() {}

There are some tricks available for the Arrow function (look it up online) 
but a common one is we do not need brackets if we collect a single parameter:
button.on("click", e=>{});

// We can also pass a function object as a parameter to be run later
timeout(1, ()=>{circle.removeFrom(); stage.update();});

// We have passed the function object as the second parameter to the timeout() method
// Alternatively, we could declare a function and pass that in as a parameter:
function remove() {
    circle.removeFrom();
    stage.update();
}
timeout(1000, remove);
// Note: that we do not call the remove function in the timeout() but rather refer to it
// This second way is longer so we often use the first way with the anonymous function

// We can also store a function as a property of an object
// All the ZIM functions (aside from the global short functions) are stored in an object called zim
// As such, we call this zim object the zim "namespace"
rand(10,20); // returns a random integer between and including 10 and 20 (more options available)
mobile(); // returns if the app is mobile and if so which type
Circle(); // is the Circle class (in JavaScript, a class is a function)


// ---------------------------------
// EVENTS
// CreateJS provides an on() method to add events and an off() method to remove events
// These replace the traditional addEventListener() and removeEventListener() methods in JavaScript
// The immediate benefit is that they are shorter!
// They work the same way but have a few conveniences:
const circle = new Circle().center();
let score = 0;
circle.on("click", () => {
    score++;
});
// We can automatically remove the event once it runs once:
circle.on("click", () => {
    score++;
}, null, true); // the fourth parameter set to true makes the event run once

// Note: above we use the anonymous function as the second parameter
// We could declare the function and use the function reference instead:
function addScore() {
    score++;
}
circle.on("click", addScore);
// As mentioned, this is longer so we tend to use the arrow or anonymous function


// ---------------------------------
// EVENT OBJECT
// The event functions receive an event object with extra information
// Imagine that we have a zim Container called monsters with 100 monster objects inside
monsters.on("click", e => { // e is the event object
    e.target.removeFrom();
    // e.target is whatever monster caused the event so one monster will be removed
    // e.currentTarget is a reference to the object the event was put on - so in this case, monsters
    stage.update();
});

// Note: ZIM drag() uses the event object to drag an object in a container:
monsters.drag(); // would drag which ever monster inside monsters is pressed
monsters.drag({all:true}); // would drag all the monsters

// Here we use the event object to find out which key is pressed:
frame.on("keydown", e => {
    zog(e.keyCode); // will tell you the code of the key
    if (e.keyCode == 32) {zog("spacebar");}
});


// ---------------------------------
// MODULES
// ZIM and CreateJS use the module pattern to give a "namespace" object
// The module pattern allows you to use the same namespace across scripts
// This allows you to use only the modules you need and combine these in any order
// ZIM was initially provided as modules (code, display, methods, controls, frame, etc.)
// but this was discontinued in favor of ZIM DISTILL (see below)

// You can use the module pattern in your code
// Perhaps you want to store code for each page of your app in separate files
// you would then import each page at the top of your main HTML page:
<script src="page1.js"></script>
<script src="page2.js"></script>

// Here is what the module pattern would look like:
// this is inside page1.js:
var app = function(app) {
    app.makePage1 = function() {
        zog("page1");
    };
    // etc.
    return app; // return the object with its properties to the outside
} (app || {}); // the app namespace object if it exists OR an object literal if it does not

// this is inside page2.js:
var app = function(app) {
    app.makePage2 = function() {
        zog("page2");
    };
    // etc.
    return app; // return the object with its properties to the outside
} (app || {}); // the app namespace object if it exists OR an object literal if it does not

// then in your main HTML page you can call the remote functions:
app.makePage1();
app.makePage2();

CREATEJS
HIDE

// CreateJS is an open source library of JavaScript modules for the HTML Canvas
// https://createjs.com
// CreateJS (specifically EaselJS) gives us the stage, basic display classes and events
// These generally follow the structure and names found in Adobe Flash
// The Display classes are Bitmap, Shape, Container, Text, Sprite and MovieClip

// CreateJS also has SoundJS, PreloadJS and TweenJS modules
// that are used by ZIM Frame loadAssets() and the move() and animate() methods

// EXAMPLES
// To use CreateJS classes, use the createjs namespace:

const container = new createjs.Container();
stage.addChild(container);

// you cannot use any of the dozens of ZIM METHODS
// for instance, you cannot use container.center();
// nor can you use container.drag(); etc. because these are ZIM

// you can use a ZIM METHOD as a zim function:
zim.center(container, stage);
zim.drag(container);

// or you can zimify a CreateJS object:
zimify(container); // then you can use ZIM METHODS

// BETTER SOLUTION
// The above is annoying so in ZIM 4TH, we made a major change:
// ZIM extends all the basic CreateJS display classes
// The ZIM classes are pretty well the same as the CreateJS classes
// except they have all the ZIM METHODS
// and they have width and height parameters and properties
// The Sprite class in ZIM is also modified to match ZIM animations

const container = new Container().center().drag();

// DON'T FORGET
// because ZIM classes extend CreateJS classes
// they also have all of the original CreateJS methods and properties
// the ZIM docs mention these but you will need to go to CreateJS
// to read about their details https://www.createjs.com/docs/easeljs/

// CreateJS METHODS:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.

// CreateJS PROPERTIES:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, mouseChildren, mouseEnabled, parent, numChildren, compositeOperation, etc.

// CreateJS EVENTS:
added, click, dblclick, mousedown, mouseout, mouseover,
pressmove, pressup, removed, rollout, rollover

PRINCIPLES
HIDE
// ZIM is Object Oriented - see the ZIM Learn Tutorials for full definition videos


// CLASS and OBJECT
// A class is a template from which an object is made using the new keyword
const rect = new Rectangle(); // Rectangle is the class, rect holds the object


// METHODS
// A method does something to an object or lets the object do something (verb)
// We use the dot syntax . to say that a method belongs to an object
rect.addTo(); // adds the rect to the stage
rect.drag(); // lets the rect be dragged
// (a method is a function that belongs to an object)


// PROPERTIES
// A property describes the object or is something the object has (adjective)
// We use the dot syntax . to say that a property belongs to an object
rect.color = red; // sets the color of the rect to red
zog(rect.alpha); // gets the transparency of the rect
rect.x = 20; // positions the rect to 20 pixels
// (a property is a variable that belongs to an object)


// EVENTS
// An event is when something happens like a click, a load, a resize, etc.
// We use the on() method to capture these and run a function
rect.on("mousedown", e => { // using a function literal as second parameter
    rect.rotation += 90; // add 90 degrees to the rect rotation
    // e is an optional event parameter that collects extra information
    // such as e.target which gives what caused the event
    // this is useful for events on containers of multiple objects
});


// ZIM is filled with Classes, Objects, Methods, Properties and Events
// The documentation has a section detailing each of these
// You can make your own as well - see the ZIM Learn Tutorials about this

PROGRAMMING
HIDE
// ZIM and CreateJS are programmed in JavaScript
// So you are programming in JavaScript when you code in ZIM
// JavaScript has all the traditional programming basics
// See the ZIM Learn Tutorials What IZ section for detailed videos
// Here are some very quick definitions:


// SYNTAX
// When coding you have to use certain characters in certain places
// If you get this wrong, there is often an error shown in the console (F12)
// You can only use words that are language keywords or that have been defined correctly


// OPERATORS
// operators (often one character) are part of the coding languages
// arithmatic: + - * / %
// assignment: =
// comparison: == < > <= >= !
// ; ends a statement, etc.


// PRIMATIVES
"string"; // a String is a collection of letters, like a word or words
7; // a Number needs no quotes and is... a number
true; // a Boolean true or false
// these are also wrapped in JavaScript objects but don't worry about that


// EXPRESSIONS
// An expression is anything that evaluates to an object
// 10 + 10
// "hello " + name // + is concatenation here (append)


// STATEMENTS
// A statement ends in a semi-colon;
// It is a combination of operators and expressions
let x = speed + 10;
// These are usually on one line each but they do not have to be
let y = 20; let z = "30"; // two statements on the same line
// Sometimes we leave off the ; which still works if the statement is on its own line
// and if JavaScript is in a non-strict mode (default)


// BRACKETS
// Brackets always have matching pairs
// {} are used to hold a block of code that will be usually be done in order (or an object literal)
// [] are an Array literal
// () are used for order of operation and for parameters
// When we nest brackets often we indent to help us keep track


// VARIABLES
// A variable is used to hold or refer to an object (the object can change)
// It is like a container with a label (name or identifier)
// Here we use the keyword var to declare a variable with an identifier x
// We then assign the variable x the number 7 using the assignment operator:
var x;
x = 7;
var y = 9; // or we usually declare and assign in one statement

// In ES6 we were given two more keywords for declaring variables - const and let. 
// const is for when we will always keep the same object in the variable. 
// let is for when we may change which object is stored.
// We use const and let now more than var as they more specifically show what we intend 
// this can help us debug as code gets more complex.

const a = 10; 
a = 15; // would give an error because we cannot change the 10 object to the 15 object.
let b = 5;
b = 20; // would be fine. 

// we can mutate the object - as in, change its properties
const circle = new Circle(); 
circle.color = red; // fine as we do not change the object stored.

// let is also scoped to any brackets {} it is declared in - eg. function, for, or if blocks.
// the ES5 var is scoped to any function brackets {} it is declared in.


// CONDITIONALS
// A conditional tests to compare the value of an expression
// Here we use the if else keywords round brackets and curly brackets
// to make a conditional expression
// We use the comparison operator == to test if x is equal to 7
// We run the first block of code if the x == 7 Boolean expression is true
// We run the second block of code if the x == 7 Boolean expression is false
// These blocks of code could have many statements:
if (x == 7) {
    //do this;
} else {
    //do this;
}


// FUNCTIONS
// A function declares a block of code to be run any time the function is called
// Here we declare a function with an identifier of test
// We collect a parameter (like a variable) called n
// and we define a block of code that does a conditional test on n
// If the test is true we return true and otherwise we return false
// return is a keyword that makes the function end and send back a value

// We can make functions without parameters
// We can make functions that do not return a value
// It depends on what we want the function to do

// Finally, we execute or run the function by using the identifier and ()
// Note, here we are passing the value of x into the function
// This means that we will be testing whatever x is
// x happens to be 7 from above so we have 7 * 5 = 35 which is less than 50
// So test(x) would have a value of Boolean false
function test(n) {
	// we indent the block of code to make it easier to read
	// as we start nesting code, indenting is very important
	if (n * 5 > 50) {return true;}
	return false;
}
test(x);
// We can call this function anywhere in the code as many times as we want
// We can even call the function before we define it
// JavaScript will "hoist" the declarations and definitions to the top automatically


// LOOPS
// A loop repeats a block of code while a condition is true
// Here we loop starting with a variable i having a value of 0
// We keep looping as long as i is less than 10
// Each time we finish a loop we add one to the value of i
// The i++ is a short form for i = i + 1
// Each time we loop we do what is in the block of code
// So we would execute (call) the function makeMonster ten times:
for (let i=0; i<10; i++) {
	// note that we indent the block of code
	makeMonster();
}


// ARRAYS
// An Array is a list of variables each with an index that increases from zero
const a = [red, green, blue, yellow];
a[0]; // refers to the first element in the array red
zog(a[1]); // displays green in the console window
a[0] = "pink"; // assigns "pink" to first element of the array
// You can nest arrays too
const b = [["a","b","c"],["d","e","f"]];
zog(b[0][1]); // b


// OBJECTS
// An object literal is a collection of properties each with a value that we access via identifier
const o = {name:"Dan Zen", occupation:"Inventor"}
o["name"]; // has a value of "Dan Zen"
o.name; // is the same thing and has a value of "Dan Zen"
o["occupation"] = "Professor"; // replaces "Inventor" with "Professor"
o.occupation = "Inventor"; // puts "Inventor" back into occupation