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

TIPS

GLOSSARYTOP
Here are some terms that we use in our world of ZIM.

TIMETOP
TIME is a constant introduced in ZIM Cat that defaults to "seconds". Earlier ZIM examples and videos use "milliseconds" for animate(), wiggle(), timeout(), interval() and others.

new Circle().center().amimate({scale:2}, 1000); // nothing appears to happen!


Above will now take 1000 SECONDS and give a console warning. You want:

new Circle().center().amimate({scale:2}, 1);


To go back to Milliseconds use
TIME = "milliseconds";
or
TIME = "ms";
.
NAMESPACETOP
Many ZIM examples and videos use the zim namespace - for instance:

const circle = new zim.Circle();


This is no longer required so you can just use:

const circle = new Circle();


Another example is
zim.rand(20)
can now be just
rand(20)
. See the news post.
CHAININGTOP
You can chain almost all ZIM methods. For example:

new Circle()
  .center()
  .mov(100)
  .drag();


Note the semi-colon is at the end. Putting these on multiple lines allows you to comment out individual commands for testing. Do NOT chain the CreateJS
on()
method for events and do NOT chain properties. ZIM provides a number of equivalent chainable methods like:

pos(), loc(), mov(), sca(), alp(), hov(), rot(), reg(), siz(),
ske(), tap(), hov(), cur(), top(), bot(), ord(), sha()


Other methods can be chained too such as

center(), centerReg(), cache(), setMask(), etc.


Do NOT use
scale()
as it conflicts with CreateJS 1.0 but rather use
sca()
. See the Bubbling video.

In general, to confirm that a ZIM method returns the object, check at the bottom of the docs for that method under the RETURNS section. If it says returns obj for chaining, then you are good to chain!
CONFIGURATIONTOP
Configuration Objects are object literals { } that hold properties that match the parameter names for classes and functions. The ZIM DUO technique allows us to pass in parameters individually or as a single parameter that is a configuration object. For example:

// traditional parameters in order:
const rect = new Rectangle(100, 100, red, null, null, 20);

// or as a configuration object:
const rect = new Rectangle({width:100, height:100, color:red, corner:20})
;

Configuration Objects can be clearer and can be considerably shorter. Also, the order of the properties in the configuration object does not matter. On the other hand, if you are using only the first couple parameters, configuration objects could take longer to type.

RECOMMENDATION: switch between the two depending on the situation. If you need a parameter that is many parameters along, then a configuration object will be better. If you are using a few parameters in order, then traditional parameters are fine.

See the Parameter sections of the ZIM Docs to see if a class or function accepts ZIM DUO. You can also make your own classes and functions work with configuration objects by using zob.
DYNAMICTOP
In ZIM VEE (version 5) ZIM launched a system of dynamic parameters. These are values that can be be passed to parameters and then picked later by the function, method or class. In the docs, they are refered to as ZIM VEE values. The formats are:
  1. a random selection: ["blue", "green", "yellow"] - array format
  2. a random range: {min:10, max:30} - range object format
  3. a series: series(10,20,30) - series format also Pick.series()
  4. a function result: function(){return new Date().minutes} - function format
  5. a normal value: 7 or "hello" - single-value format
  6. a noPick object: {noPick:["real", "array"]} - escape format
  7. a combination: [{min:10, max:20}, 30, 40] - combination format (recursive)
You can use them to make tile a series of objects, to emit different particles each time. To make an interval go at a range of times, etc. Here is an example:

new Tile(new Circle({min:20,max:50}, [red,green,blue])).center();


You can also use ZIM VEE values in STYLE to apply styles in order or randomly. See the STYLE tip. See also SERIES for options like reverse(), bounce(), constrain(), step(), every() and jump(). See PICK to use dynamic parameters in your custom methods, functions or classes.
POSITIONTOP
There are a variety of ways to add and position objects. See https://zimjs.com/positioning/. You can also use x, y, regX and regY properties - but generally, we use the following chainable methods:
  1. addTo(container, index, localToLocal)
    • use to add to a container at current x and y
    • note: objects, when created, have an x and y of 0
    • default container is stage - can set index
    • keeps visual positon when changing containers
    • unless localToLocal is set to false

  2. center(container, index, add)
    • use to center on and add to container
    • default container is stage - can set index
    • can choose not to add

  3. centerReg(container, index, add)
    • use to center registration, center on and add to container
    • default container is stage - can set index
    • can choose not to add

  4. loc(target|x, y, container, index, add, localToLocal)
    • use to place object at the location of a target object
    • or use to locate the registration at an x and y
    • default container is stage - can set index
    • can choose not to add
    • if target is in another container will still place on target
    • unless localToLocal is false

  5. pos(x, y, horizontal, vertical, container, index, add, reg, regX, regY)
    • NOTE: updated in ZIM 10.6.0 to use horizontal and vertical parameters
    • horizontal can be LEFT (default), CENTER / MIDDLE, RIGHT constants
    • vertical can be TOP (default), CENTER / MIDDLE, BOTTOM constants
    • use to add to container and to easily position around edges or from center
    • setting RIGHT will position right side of bounding box from right side of container
    • setting BOTTOM will position bottom side of bounding box from bottom of container
    • setting CENTER will center object then move the amount specified in x or y
    • default container is stage - can set index
    • can choose not to add
    • set reg to true to position the registration point
    • ** many examples use the old registration point pos()
    • ** the new pos() will work the same way for reg(0,0) objects
    • ** but will work differently for other registrations or rotated objects
    • setting POSREG = true; will default all pos() to reg based
    • but would recommend using loc(x,y) for registration positioning

  6. mov(x, y)
    • use mov() to set relative position
    • does NOT add to a container

  7. reg(x, y)
    • use reg() to change the registration point
    • the object will appear to shift
    • yet its x and y values will remain the same
    • does NOT add to a container

The following code tools are available to help position objects:

  1. place(id)
    • use place() to pick up object and place
    • you can also use key arrows and shift key arrows
    • the console (F12) will show location
    • hard code with loc() in code and delete place()

  2. placeReg(id)
    • use placeReg() to set registration point
    • the console (F12) will show location
    • hard code with reg() in code and delete placeReg()

  3. new Grid(obj, color, percent)
    • tool to see absolute location
    • add a Grid to a container obj (default stage)
    • use the cursor to find x and y values
    • use pos() in code to apply distance
    • set percent to false to see pixels
    • or press the p key to toggle
    • remove the Grid when done

  4. new Guide(obj, vertical, percent)
    • tool to see relative location
    • add a Guide to a container obj (default stage)
    • can use vertical and horizontal
    • use the cursor to find x and y values
    • at a distance from the guide
    • use mov() in code to apply distance
    • set percent to false to see pixels
    • or press the p key to toggle
    • remove the Guide when done
LEVELSTOP

Each DisplayObject (Circle, Button, Container, etc.) is placed in its container at a certain level (layer) starting with 0 at the back and increasing in index number to the front. This is similar to layers in Photoshop or Flash and to z-index in CSS. When things are added they are placed on top but a specific level can also be given as follows:

new Circle().addTo(container, level);
new Circle().loc(x, y, level);
new Circle().pos(x, y, horizontal, vertical, level);
new Circle().center(container, level);
new Circle().centerReg(container, level);


Note - objects behind other objects might not be seen.

The following methods and properties are available to set levels:

  1. top()
    • moves object to top of container
    • chainable zim method

  2. bot()
    • moves object to bottom of container
    • chainable zim method

  3. ord(num)
    • moves object relatively up or down
    • ord(-1) moves down a level, ord(-3) down three
    • ord(1) moves up a level, ord(2) moves up two
    • chainable zim method

  4. parent.addChildAt(obj, level)
    • CreateJS method, not chainable
    • note this is on the parent

  5. parent.setChildIndex(obj, level)
    • CreateJS method, not chainable
    • note this is on the parent

  6. parent.getChildIndex(obj)
    • CreateJS method, not chainable
    • note this is on the parent

  7. parent.swapChildren(obj1, obj2)
    • swaps the location of two children
    • note this is on the parent

  8. parent.swapChildrenAt(index1, index2)
    • swaps two children based on index
    • note this is on the parent

  9. parent.removeChildAt(index)
    • removes a child at an index
    • note this is on the parent

  10. parent.sortChildren(sortFunction)
    • sorts children of a container
    • make a function that returns 1,-1 or 0

  11. obj.numChildren
    • read only to find the number of children in container

JAVASCRIPT 6TOP
JavaScript 6 (ES6) is now being used in the ZIM Template, ZIM Skool, CodePen examples, etc. However the earlier examples are ES5 based. Here are the two most common differences:

// 1. Instead of var we use const or let
// const is for always holding the same object
// let is for variables that may change objects (see stageW, stageH below)

const frame = new Frame(); // always the same Frame object

frame.on("ready", () => { // 2. ES6 Arrow Function - short for function(){}

    const stage = frame.stage; // the only object to be stored in stage
    let stageW = frame.width; // stageW changes number objects when window is resized
    let stageH = frame.height; // so width and height are not constants here

    const circle = new Circle().center().drag();
    circle.color = red; // okay to change properties of constant

    frame.on("resize", e => { // arrow functions with one param do not need ()
        stageW = e.target.width; // or frame.width
        stageH = e.target.height; // note we change width and height objects
        circle.loc(stageW/2, stageH/2); // or center() ;-)
        stage.update();
    });

});


FRAMETOP
ZIM Frame creates a canvas tag, the stage and scales these in a variety of ways. We recommend that you use the frame available on the CODE page - just copy the tempate! See the FRAME page for more templates like Full window, Fit to the window, fitting in an existing HTML tag and act just like an image - except an interactive image!

Frame can be used to load assets in its assets parameter:

const frame = new Frame({assets:["asset.jpg", "sound.mp3"], path:"path/"});

frame.on("ready", () => {
    const pic = asset("asset.jpg").center();

    // note sounds cannot be played until there is a first interaction
    // so for a background sound, make a start button or intro screen, etc.
    pic.on("click", ()=>{
        asset("sound.mp3").play();
    });

    // this is needed to show display objects on stage
    // in template, frame.stage is stored in const stage
    frame.stage.update();
});


OR at any time in your code with frame.loadAssets():

// inside your frame "ready" event function
// at any specific time you want to load assets - also see 8. IMAGES below.

    frame.loadAssets(["pic.png", "sound.mp3"], "path/");

    frame.on("complete", () => {
        asset("pic.png").center();
        asset("sound.mp3").play(); // assuming later after interaction...
        frame.stage.update();
    });


There are more options (such as techniques for multiple loadings) and events when loading - see the ZIM Docs.

MULTIPLE FRAMES

You can use multiple frames on the same page and even overlap frames. There are some tricks, though!

FRAMES ON HTML OR OTHER CANVASES

You can put ZIM above or below other HTML or Canvas tags. See OVERLAY example. Here is a VIDEO about overlaying ThreeJS and ZIM. Unfortunately, only one canvas or the other can have the interactivity.

Here are some tips on overlaying on HTML like the ZIM FRONT PAGE.

// to overlay ZIM with no interactivity on HTML

var frame = new Frame({
    scaling:"full", // or other scaling options
    captureMouse:false,
    rollover:false,
    allowDefault:true // let HTML scroll, page up, wheel, etc.
});

// styles can also be used to do just about anything you want with the canvas
frame.canvas.style.position = "absolute";
frame.canvas.style.zIndex = -1; // or 5 for above, etc.
frame.canvas.style.pointerEvents = "none";

IMAGESTOP
Images can be loaded with Frame - see FRAME above. When you view images from the Web LOCALLY in a Browser on the Canvas, there is a security error that mentions CORS (cross origin resource sharing). The issue will go away when on a SERVER. This is a general (not just ZIM) JavaScript Canvas security for local viewing.

To solve the issue, you can use a Browser package in your editor such as Atom or Sublime. Or start your favourite Browser as follows:

/*
ON FIREFOX:
type: about:config into your Browser URL bar
search for security.fileuri.strict_origin_policy and double click it to set it to false

ON PC CHROME:
To test locally, find your Chrome icon or shortcut, right click and choose properties
then under Target, adjust your target to include --allow-file-access-from-files (after the quotes)
eg. "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files
** You must always start your first Chrome window from this shortcut

ON MAC CHROME:
open your terminal anywhere, make sure Google Chrome is currently not running
copy paste this line and hit enter:
open -a "Google Chrome" --args --allow-file-access-from-files
*/


Now Frame can be used to load assets in its asset parameter. If you want more than one copy of an asset then use the clone() method.

const frame = new Frame({assets:"asset.png", path:"path/"});

frame.on("ready", () => {
    const stage = frame.stage;

    asset("asset.png").center();

    // note: if you want two or more copies of the image then use clone()

    asset("asset.png").clone().pos(100,100);

    stage.update();
});


Also, make sure that if you are loading an absolute URL to use https://

ZIM can now load assets without checking for CORS (so bypassing the CORS test) as follows:
See this example

// use the noCORSonImage property of the ZIM asset object when loading the image:

assets:{id:"special", src:"https://url.jpg", noCORSonImage:true}


SOUNDTOP
Sounds can be loaded just like pictures inside the Frame asset parameter or later with the Frame loadAssets() - see FRAME above IMAGES.

Warning! When you load assets from the Web LOCALLY in a Browser on the Canvas, there is a security error that mentions CORS (cross origin resource sharing). See the IMAGES section above as to how to deal with that locally.

Warning! Sound cannot be played before the user interacts with the page - this is a general Browswer rule to stop being bombarded with sounds. It means that you will have to make a start button or a splash page that the user interacts with before a background sound can be played.

To play a sound use the play() method on the sound asset() which can be passed a configuration object with the following properties: volume, loop, loopCount, offset and pan.

The return value of the play() can be stored in a variable and can be used to set a "complete" event to find when the sound finishes. It also has volume, pan, duration and paused properties.

const frame = new Frame({assets:"sound.mp3", path:"path/"});

frame.on("ready", () => {

    stage.on("stagemousedown", ()=>{
        // note sounds cannot be played until there is a first interaction
        // so for a background sound, make a start button or intro screen, etc.

        // use the play() right on the sound asset
        // could add loop:true, loopCount:2 into play, etc.
        const sound = asset("sound.mp3").play({volume:2});

        // adjust the sound after...
        timeout(1, ()=>{ // time in seconds as of ZIM Cat
            sound.volume = 1;
        });
        timeout(2, ()=>{
            sound.paused = true;
        });
        timeout(3, ()=>{
            sound.paused = false;
        });
        sound.on("complete", ()=>{
            frame.color = red;
            stage.update();
        });

    }); // end stagemousedown
}); // end frame ready


Also, make sure that if you are loading an absolute URL to use https://

COLORSTOP
ZIM started off with special colors stored on the Frame - frame.green, frame.blue, etc. These have become very well used and there are times the colors are needed before the Frame loads. So, now the colors are available on the ZIM namespace or GLOBALLY if the namespace is not required.

green, orange, blue, pink, brown, yellow, purple, red


As well as shades such as:

dark, darker, light, lighter, grey, tin, silver,
fog, mist, moon, white, black, faint, clear


We tend to use these in ZIM examples but any HTML/CSS string color will do such as:

"red", "#CC0000", "#333", "rgba(0,0,0,.2)", etc.


You can also use color lighten() and darken() methods or convert colors and animate between colors:

new Rectangle(100, 100, red.darken(.5));
frame.color = purple.lighten(.1);
const faintBlue = convertColor(blue, "rgba", ".5");
new Circle(100, red).animate({color:faintBlue}, 1000);


COLOR CHANGES: as of ZIM OCT (8) color parameters across the components have changed:
  • color and rollColor now refer to text color
  • backgroundColor and rollBackgroundColor refer to the component color
In many of the earlier ZIM examples and videos, color was the background color and the text color could only be set through a custom Label. This has changed many of the parameter names and the order of the parameters in some places. All changes can be found in the ZIM Docs Updates Page

ZIM DisplayObjects now accept GradientColor(), RadialColor() and BitmapColor() objects - take a look in the docs for how to use these.
EVENTSTOP
In general, use the on() method to capture events such as:

"click", "dblclick", "mousedown/pressdown", "pressmove", "pressup",
"mousemove", "stagemousemove", "mouseover", "mouseout"
"ready", "complete", "change", "keydown", "keyup"


This is like the traditional JavaScript addEventListener() but shorter and with a few extra features:

// BASIC EVENT
const button = new Button().center();
// the type of event as a string and the function to call
button.on("click", ()=>{
    zgo("https://zimjs.com", "_blank");
});

// alternatively, using a named function
button.on("click", doClick);
function doClick() {
    zgo("https://zimjs.com", "_blank");
}

// EVENT OBJECT
const tile = new Tile(new Rectangle(), 5, 5, 2, 2).center();
tile.on("mousedown", e=>{ // collect the event object in parameter e
    // e.target is the object that caused the event (one of the rectangles)
    e.target.alpha = 0;
    // e.currentTarget is the object on which the event is placed (the tile)
    e.target.mov(5);
    // do not forget to update stage in events if needed!
    stage.update();
});

// REMOVING EVENT
let keyEvent = frame.on("keydown", e=>{
    zog(e.keyCode); // will tell code for key pressed
    // etc.
});
timeout(2, ()=>{ // time in seconds as of ZIM Cat
    // remove the keyEvent
    frame.off("keydown", keyEvent);
});

// RE-ADDING EVENT
timeout(4, ()=>{
    // add the keyEvent back again
    // note - the event must be re-assigned to use again
    // this leads to a tricky bug if not careful!
    keyEvent = frame.on("keydown", keyEvent);
});
timeout(6, ()=>{
    // remove the keyEvent again
    // this only works if we re-assigned the latest event to keyEvent
    // which is why we used let rather than const
    frame.off("keydown", keyEvent);
});

// ONE EVENT CALL
// call this function only once when mousing over the stage
// note: "mousemove" would only trigger if moving over an object on the stage
stage.on("stagemousemove", ()=>{
    pauseAnimate(false); // unpause all animations
}, null, true); // this true means remove the event after calling it once

// REMOVE METHOD
// a remove() method is available on the event object
const circle = new Circle();
circle.on("mouseover", e=>{
    circle.alpha -= .1;
    if (circle.alpha <= .5) e.remove();
});


The on() method should NOT be chained. ZIM provides several chainable methods as alternatives:

// TAP
// tap() is like a "click" but the mouse needs to stay in the same area
new Rectangle().center().tap(e=>{
    e.target.rotation += 5;
    stage.update();
});

// CHANGE
// all objects that have a "change" event have a change() method
new Slider().center().change(e=>{
    zog(e.target.currentValue);
});

// MOVEMENT
// There is NO "mousemove" event on a DisplayObject other than on the stage
// To get movement anywhere on the stage (even off objects) use "stagemousemove"
// For movement on an object put the "mousemove" event on the stage
// and use e.target to test for the object you want
// OR use the chainable movement() method with callback:
new Circle().center().movement(()=>{
    circle.alpha -= .01;
    stage.update();
});

// HOV
// hov() can be applied to any DisplayObject
// this is like "mouseover" and "mouseout" events
// most components like a Button already handle this
// alpha if number and color if string
new Circle().alp(.5).center().hov(1); // full alpha on hover

// HOLD
// a press and hold
new Triangle().center().hold(e=>{
    e.target.removeFrom();
    stage.update();
});
MISSINGTOP
When you are coding, sometimes things do not show up. Here are some reasons why that might happen:
  • The Internet is down - the console (F12) will say Frame is not a function
  • You have an error - see console and look for message in red
  • If have images or sound and the error says "CORS..." then see IMAGES
  • You forgot to add object to the stage - use addTo(), center(), centerReg()
  • You forgot to update the stage - use stage.update()
  • You forgot to put stage.update() at the end of an event function
  • When adding to a container, remember to add the container to the stage
  • The thing that is missing might be underneath something else - see LEVELS.
  • You are animating something in and using milliseconds rather than seconds - see TIME.
  • You are viewing the wrong file - use zog() to detect this mistake
This last tip is the ZEN FIVE MINUTE rule of debugging. If you have been trying to fix something for more than five minutes - no matter what - confirm that you are viewing the file that you are updating.
INDENTINGTOP
Indenting is very important - it is how we organize our code. Imagine taking a book and making paragraphs from every four sentences. You can still read the book, but you will be left puzzled quite often.

Indenting is equivalent of putting things in boxes - boxes within boxes. This lets us see the code at multiple levels when we are planning or debugging. We can easily skip over whole sections just by looking at the indenting. Indenting is the product of hierarchy - of abstraction - a key concept in coding and in life.



RULES:
There are very easy and consistent rules for indenting. These are somewhat clouded by chaining but here they are:
  1. Indent inside { } when on multiple lines - think of these as a box.
  2. Indent using a single tab (not two or three - not spaces)
There... not so hard! Here are some extras:
  1. Indent when chaining on a new line but stop indenting at the end of the statement;
  2. If your indents are too small, change them in your preferences
EXAMPLES:
Look at the code examples on this page. Or look at every single example on the ZIM site - over 1,000,000 lines of code. You will not find a single indent out of place. That is the importance of indenting. "You will code more efficiently by perfecting indentation" - Dr. Abstract.

FIXES TO INDENTING:
This code was received in Slack. In general, the indenting is not that bad. The first line could have been a copy and paste error into Slack. And the different number of characters for the indents come from copying from different files - but would highly recommend fixing.



Below are the areas of concern. These will undoubtedly be fixed at some point - but the sooner the better. As a rule - do not go forward until your indenting is fixed. EVER. Once again, not too bad... certainly seen worse. But even the few indent errors here make the code hard to read.



INDENTING TIPS:
  1. To fix a different indent size, select the lines and shift tab until they hit the edge then tab into the right position.
  2. When copying (or cutting) and pasting, paste at the same tab indent as when copying or cutting. If you cut from the very left, paste at the very left. If you cut 4 tabs in then paste 4 tabs in.
  3. In many editors (like Atom and Sublime) sitting at a bracket will show you the matching bracket.
  4. Some editors will draw lines connecting tabs and some will provide collapsible blocks.
  5. Remember to set your tab indent to at least 4 characters. The default 2 characters is too small which encourages double tabbing or adding spaces - bad habbits!
STYLETOP
As of ZIM OCT (8) STYLE can be used to define default values for DisplayObject (shapes, components, etc.) parameters:

STYLE = {corner:0, backgroundColor:yellow};


All DisplayObjects will have these styles. You can style a type of object and these will override the general styles:

STYLE.type = {Button:{corner:20, scale:2, bacgkroundColor:"ignore"}};


Now, Buttons will have corners of 20 and be scaled twice as big. The Buttons will also ignore any previous backgroundColor style so they will be the original default (orange).

You can style a group of components and these styles will override the earier styles:

STYLE.group = {customize:{center:true, transform:true}};

new Button({group:"customize"});


The Button will have transform tools applied along with the other styles. You can add any number of objects to a group and objects can be part of more than one group with a comma separated string. Other functions can be applied with styles too, read the STYLE Docs for more features.

As of ZIM Cat, there is a Style class that has helper methods for organizing STYLE:

Style.add(); Style.addType(); Style.addGroup();

Style.remove(); Style.removeType(); Style.removeGroup();

Style.clear(); Style.clearTypes(); Style.clearGroups();

Style.remember(); Style.recall(); Style.clearRemembered();


Any values applied through parameters of the component will override the previous styles. You can also set ignoreStyles to true to ignore all styles for the component.

We recommend that you turn off your STYLE when you are finished with your section. It depends on how widespread you want your styles.

STYLE = {}; // or STYLE = null; or Style.clear();

// you can also turn off certain styles:

STYLE.type.Button = {}; // or Style.removeType("Button");

// starting new styles will also stop using old styles
// previous styles will not be applied to up-coming objects
// but they will remain on previously made objects

STYLE = {color:red}

// you can remember current STYLES and recall them latter

Style.remember("optionalID");
STYLE = {color:blue};
new Circle().center();
Style.recall("OptionalID");


You can animate, wiggle, move, add, centerReg and more with style. You can also provide ZIM VEE values such as an array of options to pick:

color:[red, purple, green], // random
x:series(100,200,300) // applied in order


The above styles would probably be written all in one assignment:

STYLE = {
    corner:0,
    color:[red, purple, green],
    backgroundColor:yellow,
    type:{
        Button:{
            corner:20,
            scale:2,
            backgroundColor:"ignore",
            x:series(100,200,300)
        },
        Slider:{step:1, useTicks:true, alpha:.5}
    },
    group:{
        customize:{center:true, transform:true},
        homePage:{outline:true} // apply outline() to all members of this group
    }
}
DRAGTOP
Dragging in ZIM can be done in several ways:
  • obj.drag() - the most common basic way
  • obj.transform() - addes transform box with other transforms
  • obj.gesture() - works with pinch and rotate too
  • obj.animate({props:{path:new Blob()}, drag:true}) - drag on path
  • MotionController(target, "pressmove") - jumps to and eases to location
  • MotionController(target, "pressdrag") - eases to location
  • Swiper(swipeOn, target)
Note: Squiggle() and Blob() objects get their own drag.

Here are tips for drag(). Please see the docs for the others.

// basic drag - will add pointer cursor:
new Circle().center().drag();

// drag object and keep animation of object animating:
// note - the default drag removes animation Tweens
new Circle()
    .center()
    .animate({props:{scale:2}, rewind:true, loop:true})
    .drag({removeTweens:false}); // good for Sprites too!

// with boundary of stage:
// as of ZIM Cat - boundary can now be any Display Object
// and the dragging object will be kept within its bounds
new Rectangle(w,h).center().drag(stage);

// prior to ZIM Cat - we had to calculate the bounds:
const w = 100;
const h = 100;
const boundary = new Boundary(0,0,stageW-w,stageH-h);
new Rectangle(w,h).center().drag(boundary);

// with boundary for object with center reg:
const r = 50;
const boundary = new Boundary(r,r,stageW-r*2,stageH-r*2);
new Circle(r).center().drag(boundary);

// with boundary for 200 pixels horizontal only (no vertical height):
const boundary = new Boundary(stageW/2-100,stageH/2,200,0);
new Circle().center().drag(boundary);

// drag items in a Container (a Tile is a Container):
const tile = new Tile(new Circle(30,[blue,green,orange]),20,10)
    .center()
    .drag(); // will drag individual circles

// drag items above without item coming to top:
// note: the default drag brings object to top of its container
    .drag({onTop:false}); // will leave level order same

// drag all items above - not each individual item:
    .drag({all:true}); // will drag whole container

// to stop dragging:
obj.noDrag();



Mouse Events can still be applied while dragging:

const circle = new Circle().center().drag();

// circle.on("mousedown", ()=>{ // as of ZIM Cat, "pressdown" does the same as "mousedown"
circle.on("pressdown", ()=>{
    circle.startX = circle.x;
    circle.startY = circle.y;
});
circle.on("pressmove", ()=>{
    circle.alpha = 1-Math.abs(circle.x-stageW/2)/(stageW/2);
});
circle.on("pressup", ()=>{
    // could use circle.noDrag()
    // but that would record the incorrect start position
    // so do not record user press on object
    circle.noMouse();
    circle.animate({
        props:{x:circle.startX, y:circle.startY, alpha:1},
        time:700,
        call:()=>{circle.mouse();} // let user press on object
    });
});


See ZIM Bits Drag Copy dragging a copy and ZIM Bits Snapping for snapping to objects.

See CodePen Unscramble for dragging and shifting tiles. Etc.

See ZIM Scrambler - now the Unscramble example is built into ZIM Cat!

See ZIM NIO and Groovity for dragging on paths.
LOOPTOP
ZIM loop is an easier format than a traditional
for(var i=0; i<10; i++){}
loop. Here is the format - which matches the familiar event call:

loop(10, i=>{
    zog(i); // 0-9
});

// same as ES5:

loop(10, function(i) {
    zog(i); // 0-9
});



There are lots of extra features too. Here are ways to loop through arrays, objects and containers. In the container example we loop through backwards which is important when removing children:

const letters = ["A", "B", "C"];
loop(letters, letter=>{
    zog(letter); // "A", "B", "C"
});

const person = {age:20, job:"farmer", greeting:"yo"};
loop(person, (property, value)=>{
    zog(property, value); // age 10, job farmer, greetings yo
});

const monsters = new Container(); // then fill with monster Bitmaps, etc.
loop(monsters, monster=>{
    if (monster.growl) monster.removeFrom(monsters);
}, true); // true loops backwards


See ZIM Docs for more details including start and end values, continuing or breaking from a loop, more parameters, etc.
ANIMATETOP
ZIM animate() is one of the most feature-full of ZIM methods. The Animation Example shows the basic types.

ZIM animate() is powered by CreateJS TweenJS here are some differences:
  1. animate chains to ZIM objects - not get(), to(), wait(), etc. chained to Tween()
  2. animate uses ZIM DUO with parameters in order or a configuration object
  3. animate adds features and is SIX times the size of CreateJS Tween
A good read over the Docs is well worth the time.

Note: TIME IS IN SECONDS as of ZIM Cat.

Note: DRAG MAY STOP ANIMATIONS on an object unless you use drag({allowTweens:true});

//BASIC
// basic animation - note as of ZIM Cat, time is in seconds
new Circle().center().animate({scale:2}, .5); // increase scale in half a second

// CONFIGURE
// animate() is one of the only ZIM methods that has a parameter that is an object literal {}
// we have taken great pains to flatten parameters and offer ZIM DUO as an alternative.
// but with animate we always have nested object literals when using the DUO technique:
circle.animate({props:{scale:2}, time:.5});

// MULTILINE
// to tell the difference between the two object literals
// we call the overall configuration object the animate object
// and the inner object for the properties the props object
// it is often easier to understand by using multiple lines:
circle.animate({
    wait:1, // wait one second before starting
    props:{scale:2},
    time:.5,
    rewind:true,
    loop:true,
    loopCall:()=>{zog("looping")} // also call, rewindCall, and more
});

// PROPS
// The reason for the props object is that we can animate any number of props at once
// here we animate the x and y to these positions in one second (the default time)
// note - for early versions of ZIM we could not do this
// as ZIM saw the single parameter object literal as the configuration object
// but ZIM can handle doing this now ;-)
circle.animate({x:100, y:200});

// TARGET
// for animate, the object being animated is called the target
// we can also call the animate() function on any object and pass a target as the first parameter
animate(circle, {color:red}, 2);

// DATA AND CSS
// this can be used to target an object without the animate method
// here we use the ZIM DUO configuration object to target a plain object literal:
// you can also animate CSS like this - see the docs under animate and then props parameter
const data = {count:20};
animate({target:data, props:{count:50}, time:2})
Ticker.add(()=>{
    zog(data.count); // count increases
});

// SERIES
// two or more animate objects can be added to an array to run in series
// there is more you an do with this such as mix in other objects
// set default values after the array, etc. but here are the basics:
circle.animate([
    {props:{x:200, y:200}, time:2},
    {props:{x:500, alpha:0}, time:.5}
]);

// MULTIPLE
// you can chain on multiple tweens on the same object
// if one tween stops the other try setting override to false
circle.animate({x:500}, 2).animate({scale:2}, 1);

// SEQUENCE
// an array or container can be run in sequence
// every .1s the next object in the array or container will animate
// note: setting the sequence time to 0
// will animate each object individually at the same time
animate({target:circlesArray, props:{x:200}, sequence:.1);
circlesContainer.animate({props:{x:200}, sequence:.1});

// PAUSING AND STOPPING
// animate has an id parameter that can be used to pause and stop animations of that id
circle.animate({props:{scale:2}, loop:true, rewind:true, id:"boing"});
pauseAnimate(); // will pause all animation
pauseAnimate(false); // will unpause all animation
circle.pauseAnimate(); // will pause all animations on circle
circle.stopAnimate(); // will stop all animations on circle
pauseAnimate(true, "boing"); // pause any animation with id "boing" - sprite and wiggle too

// FROM AND ANIMATE CONSTANT
// you can animate objects from a property value to the current value of the property
// this is handy - imagine setting up a scene's final position
// then animating from alpha:0 or x:-1000 to the final position!
// another cool thing is setting ANIMATE = false
// will stop the animations from happening and your scene will be in final position
// which is great for passing by animations as you are building!
ANIMATE = false; // toggle this to true to see animations or for final product
new Circle.center().animate({from:true, props:{x:-100}});


A unique strength of ZIM animate is animating on paths - see ZIM NIO. Here are some features:

  • Animate with the path property along a Blob or a Squiggle
  • The path can be adjusted by the user while animating
  • percentages of the path including negative can be sent
  • The object can be dragged on the path (animation optional)
  • The object can orient to the path and flip or not
  • The object can orient to any point while animating
  • The object can zoom based on y to give 3D effect
  • The object can shift levels based on y
  • The object can change opacity based on y
  • The object can change any property base on any property
const path = new Squiggle().center()
circle.animate({
    props:{path:squiggle},
    time:3,
    drag:true, // setting drag will automatically pause the animate
    startPaused:false // can cause the animation to go again
});


Animations can be done on Beads, LabelOnPath, LabelLetters, Shapes, Blobs, Squiggles there are all sorts of easing settings and more! Have fun exploring - the examples are good to look at!
HITTESTTOP
Often we need to test if objects are hitting. This almost NEVER happens when the code first loads. Usually it happens in a function in one of three places:

// 1. Tests all the time for when objects are moving on their own
Ticker.add(()=>{});

// 2. Use when user move object and the other objects are not moving
object.on("pressmove", e=>{});

// 3. Use when dropping an object in the trash for instance
object.on("pressup", e=>{});


Here is an example of the third:

const ball = new Circle(20).center().drag();
const can = new Rectangle(100, 200).pos(100, 100, RIGHT, BOTTOM);
ball.on("pressup", ()=>{
    // bigger shape hitting points around smaller circle
    if (can.hitTestCircle(ball)) {
        ball.removeFrom();
        stage.update();
    }
});

// ~~~~~~~~~~~~~~~~~~~
// NEW! As of ZIM Cat there is a hitTestRectCircle() so use that for above:
ball.on("pressup", ()=>{
    if (can.hitTestRectCircle(ball)) {
        ball.removeFrom();
        stage.update();
    }
});


WARNING: we could use ball.hitTestRect(can) but the ball is smaller and it could fit inside the bounds of the can. So the general rule when using hitTestRect() and hitTestCircle(), is put the method on the BIGGER object and test against the points on the Circle or Rectangle of the smaller object with the smaller object in the round brackets - hence, can.hitTestCircle(ball);

OPTIONS: there are other types of hitTests but for the most part, hitTestRect() and hitTestCircle() will be the most popular when hitting a rectangle or circle agains an unusual shape. If you have a rectangle and circle use hitTestRectCircle(). If you have two rectangular shapes and then use hitTestBounds() or two circles and then use hitTestCircles(). These last two are very fast as they use equations. The fastest way to test if the mouse (or any object) is over a cell in a grid is with hitTestGrid() - see Docs. This also uses a mathematical calculation rather than comparing color/point based intersection which is used by a mouseover event. See the ZIM Bit or the ZIM Capture on hitTests.

There is also hitTestPath that tests the shape of the object against a Squiggle or a Blob.

HITTING TOO MANY TIMES! If your hitTest keeps telling you it is hitting and you only want to know once... for instance, to play a sound or add 1 to a score, etc. then you may end up playing the sound over and over very quickly or adding too much to your score. You will need to either:

// 1. Remove one of the objects so they are not hitting:
if (ball.hitTestRect(rect) {
    ball.removeFrom();
    sound.play();
}

// 2. Remove the Ticker or event that is calling the hitTest:
let ticker = Ticker.add(()=>{
    if (ball.hitTestRect(rect)) {
        Ticker.remove(ticker);
        sound.play();
    }
});
// OR
let mousemoveEvent = stage.on("stagemousemove", e=>{
    // see Tip for RETINA as to why we do not use e.stageX and e.stageY
    ball.loc(frame.mouseX, frame.mouseY);
    if (ball.hitTestRect(rect)) {
        stage.off(mousemoveEvent);
        sound.play();
        stage.update();
    }
});

// 3. Use a check variable (just some logic!):
let hitCheck = false;
ball.on("pressmove", ()=>{
    if (!hitCheck && ball.hitTestRect(rect)) {
        hitCheck = true;
        sound.play();
    }
});
// you may need to set hitCheck to false some time later
// if you want to test for another hit!  ;-)


MULTIPLE OBJECTS: Often we want to test if something is hitting multiple objects. To do this, put the objects in a Container, loop through the container in the Ticker or event function and test each object:

const circles = new Container().addTo();
loop(20, ()=>{
    // ES6 tip - use let inside loop
    let circle = new Circle(20, green).loc(rand(stageW), rand(stageH), circles);
    circle.collected = false;
});
const collector = new Rectangle(50, 100).center().drag();
collector.on("pressmove", ()=>{
    circles.loop(circle=>{
        if (!circle.collected && collector.hitTestCircle(circle)) {
            circle.sca(.5);
            curcle.color = black
            circle.collected = true;
            score.text = Number(score.text) + 1;
            stage.update();
        }
    });
});


REMOVING: when looping through a container or an array and removing an object, for instance, if the object that the collector hits is removed, then you MUST loop in reverse. This will make sure that the index numbers remain the same otherwise you will get intermittent errors. To loop backwards use true as the next parameter value in the loop:

collector.on("pressmove", ()=>{
    circles.loop(circle=>{
        if (collector.hitTestCircle(circle)) {
            circle.removeFrom();
            stage.update();
        }
    }, true); // the true makes loop loop in reverse
});
DISTILLTOP
ZIM is over 200K in size and growing but you can easily use Distill to create a minified file of only the ZIM code that you are using. In your scripts, before you call ZIM Frame, add the following:

DISTILL = true;


This starts a recording of function numbers. When your code is done (i.e. in a click event function) add the following:

distill();


At this point, a coded list of all the functions that have been used are displayed in the console (F12). Copy this list and go to the Distill page where you can paste them into the form and submit to receive the distilled minified code - and non-minified code for your reference. You can then paste this code in a remote JavaScript file and call it from your page instead of the full ZIM cdn link:

<script src="remote.js"></script>


Or load the code in between script tags. Here are some Examples and the Docs.
RETINATOP
ZIM Retina is here which makes ZIM vector crisp and look amazing! One change with Retina, is that the Mouse Event object mouse position needs to be divided by the stage scale:

stage.on("stagemousedown", e=>{
    let x = e.stageX/stage.scaleX;
    let y = e.stageY/stage.scaleY;
    // etc.
});
// ~~~~~~~~~~~~~~~~~~~~~~~~~
// ** Note as of ZIM Cat and ZIM's CreateJS 1.3.2, this is no longer the case
// the CreateJS has been adjusted but you can still use the frame.mouseX and frame.mouseY below if desired


To avoid this, we have provided mouseX and mouseY properties on Frame that include the scale adjust. Use these as follows:

stage.on("stagemousedown", ()=>{
    let x = frame.mouseX; // note mouseX not stageX
    let y = frame.mouseY;
    // etc.
});
CREATEJSTOP
ZIM is built on CreateJS at https://createjs.com and so all CreateJS documentation applies to ZIM. We recommend that you use the ZIM version of CreateJS as it has some helpful updates. See the top of the DOCS for the link.

ZIM Containers extend CreateJS Containers and many of the ZIM Display objects extend ZIM Containers. This means, the ZIM objects get all the CreateJS methods, properties and events like:

on(), setBounds(), x, y, rotation, alpha,
mousedown, mouseover, mouseout, pressmove, pressup, etc.


If we have a CreateJS display object such as a Container or Shape that comes from Adobe Animate, etc. then we can give this object all the ZIM display methods by using the following:

zimify(CreateJSObject);

// this gives the CreateJS object
drag(), animate(), hitTestRect(), hitTestCircle(), etc.
center(), centerReg(), pos(), mov(), etc.


It should be noted too that ZIM objects have a width, height, widthOnly and heightOnly properties. These scale the object to give the desired width and height. They leave the bounds as originally set:

const rect = new Rectangle(100,100).center();
rect.width = 200; // scales the rect by 2 in both the x and y
zog(rect.width); // 200
zog(rect.getBounds().width); // 100
zog(rect.scaleX, rect.scaleY); // 2, 2


SETTING BOUNDS - when you are creating a Container or a Shape you have the choice of setting the width and height as parameters as you make the object. You can optionally set the boundsX and boundsY and the width and height. You can also let the container make its own bounds based on its contents by leaving the container parameters as null. And of course, you can get and set the bounds at anytime using getBounds() and setBounds(). Setting the bounds to null will have the container automatically calculate its bounds. For ZIM center() and centerReg() and various hitTest methods it is often helpful or necessary to have the bounds set.
ZOGTOP
Browsers have a console (F12) that can be used by developers to see what is happening in their code. The console is not seen by the end user - although, if they know how, they can view it. There are also debuggers but these are often not needed. We can
zog()
helpful messages to the console as we code.
zog()
is just short for JavaScript's
console.log()
. There are colored zogs too! These help organize the console.

zogr(); zogb(); zogg(); zogy(); zogp(); zogo();


If you are just starting to code, it is a good idea to test often. Every time you make a function, the first thing you do should be to
zog("functionName");
inside the function to make sure the function is running. Here are a few examples of where we might use functions:

// CUSTOM FUNCTIONS
function test() {
    zog("test"); // will show test in the console when function runs
}
// this function above will not run until it is called:
test();

// EVENT FUNCTION LITERALS
object.on("click", ()=>{
    zog("clicked"); // runs when object is clicked
});

// CALLBACK FUNCTIONS
object.animate({
    obj:{x:200},
    time:2, // time in seconds as of ZIM Cat
    call:function() {
        zog("animation done"); // runs when animation finishes
    }
});

// TICKER FUNCTIONS
Ticker.add(()=>{
    // runs at the frame rate - very fast!
    // just check then comment out or delete - can bog performance
    zog("ticking");
});

// INTERVAL FUNCTIONS
interval(1, ()=>{ // time in seconds as of ZIM Cat
    zog("interval"); // runs every second
});

// TIMEOUT FUNCTIONS
timeout(.5, ()=>{
    zog("timeout"); // runs once after half a second
})

// LOOP FUNCTIONS
loop(10, i=>{
    zog(i); // shows 0-9 as we loop
}


In all of these, we would want to make sure the function is running before we start coding inside the function. If we do not, we sometimes will think that our code inside is broken - when really, it is just that the function is not running.
ERRORSTOP
Use the console (F12) to see any errors in your code - they are RED and will show a message and a line number. Sometimes the message does not make sense, or the line number seems strange. Here are some tips:
  • If the line number is at the end of the file, a bracket is probably missing somewhere in your code (not necessarily the end).
  • If the error is TypeError: ... null then you may be trying to set a property or run a function on an object that does not exist - check for typos or zog() the object to see if it exists.
  • If the error is SyntaxError: expected expression, got '.' then you probably have a semi-colon between your chaining.
  • If the error is TypeError: this.zimContainer_constructor is not a function then remember to use the new keyword when making objects.
  • If the error is TypeError: ... is not a consructor then make sure your variable name is not the same name as your class. For instance: const Shape = new Shape(); is bad!
  • If the error is TypeError: invalid assignment to const then you are assigning a different object to a constant
  • If the error is in ZIM or CreateJS then try commenting out your latest code and see if the error goes away. If so, then check the parameters of your latest code.
In general, if you can't figure out something then simplify. Comment out code until it works again. Or even try the problem code in a new file. Also remember to save your file and check to see you are testing the right file.
ASKTOP
We are here and love to help. There is no question too small and no question too big. Here is an invite to the ZIM Slack Team. It just takes a moment to sign up to Slack and it is all online. Many companies are using Slack for internal communication. Slack is being used as forums for software support, educational communications, etc. Here are the ZIM Slack channels - it helps to post in the relevant channels but you will find us all very friendly - so no worries:
  • Examples - view and show projects
  • General - posts that don't fit in other channels
  • Releases - ZIM announces each release here
  • Questions - ask how to do something
  • Random - chit-chat - maybe not about ZIM
  • Requests - what would you like to see in ZIM
CHANGESTOP
It is beneficial to keep up with changes. The ZIM News section has two main links - the Bubbling videos (started March 2017) and Blog (started March 2016) both of which highlight new features. Bubbling shows features that were added or changed since the end of the ZIM Bits series of 64 code tutorials and after the ZIM Capture video tutorials both found in the ZIM Learn section. A look through the Bubbling videos titles is a quick way to summarize changes (this list of ZIM TEN updates):

Positioning and Constants | ThreeJS OrbitControls | Animated Text | Radial Menu | DPad Keyboard Alternative | ZIM 10.5.0 Updates | List Pulldown! | Marquee! | 15 New Features! | hitTestPath | SHIM for Adobe Animate | Retina | Shape Tween Animation | ZIMON | Isometric Game Board | Node Package Manager | Model, View Controller | Intro to TEN Site | Accordion & Tip | Physics | ZIM TEN (10)

Specific and complete changes in the ZIM code can be found in the Updates page which goes hand in hand with the updates of the Docs. These show the version numbers of ZIM in major.feature.fix format:
  • The Major number is increased with an advance in structure or philosophy.
  • The Feature number is increased when there is a new display object, method or control added.
  • The Fix number is increased for adjustments and fixes.
Here is a snip of an Updates example where an IMPROVEMENT and a BREAK have been noted:

ZIM 6.3.2
Added split property to Parallax object to center the input value IMPROVEMENT
BREAK Adjusted Parallax parameter order to layers, damp, auto, stage


You may consider updating old code for improvements and if you do update, note that any breaks may require adjustment to old code - usually in the order of parameters.



Happy   C R E A T I N G   from Dr Abstract and Pragma - at ZIM!