YOUR GUIDE TO

Interactivity on the Canvas with JavaScript

Including dragging, gestures, transforms, hit tests and more!

// we see STYLE in an upcoming guide
// this is optional - just tired of rounded orange buttons
STYLE = {corner:0, backgroundColor:blue, scale:2};
const button = new Button().center();
button.on("click", ()=>{
button.mov(10);
stage.update();
});
Traditional click event on Button
// Do not chain on() 
// because it returns an id for removing the listener
const button = new Button().center();
const id = button.on("click", ()=>{
button.mov(10);
stage.update();
button.off("click", id);
});
// here is how we can remove the listener
// there are a couple ways:
// 1. use the clear() method of the event object e
// (an event object gives us more info about the event)
button.on("click", e=>{
button.mov(10);
stage.update();
e.clear();
});
// 2. or use the fourth parameter of the on() method
// this is the version we usually use:
button.on("click", ()=>{
button.mov(10);
stage.update();
}, null, true); // capture only once

Tap and Change !

ZIM has provided a few chainable methods like tap() and change() to capture common events. (There is also hold() and movement().) These receive a single callback function that will run when the event happens. The methods return the object so they can be chained.

// TAP
// captures a click event
// we could assign the button to a variable
// or here we use the target of the event object
new Button().center().tap(e=>{
e.target.mov(10);
stage.update();
});
// CHANGE
// captures a change event
// CLEAR, copy or type and TEST this:
const back = new Rectangle(stageW, stageH, darker)
.alp(0)
.addTo();
new Dial({sound:true, max:1})
.sca(2)
.center()
.change(e=>{
back.alp(e.target.currentValue);
stage.update();
});
Using change() to change properties with a component

Wire and Wired!

ZIM also provides wire() to directly wire properties together. This is an alternative to events with the on() method and is new to ZIM Cat. The wire() method connects a source to a target and the wired() method connects a target to a source. Otherwise, they are the same.

// WIRE
// connects properties
const back = new Rectangle(stageW, stageH, darker)
.addTo();
new Dial({sound:true, max:1})
.sca(2)
.center()
.wire(back, "alpha");
Connecting source and target properties with wire()

Interaction Beyond Events

Events are your basic way to capture interactivity. With ZIM, we have powerful built-in methods for interactivity. These include drag(), gesture(), transform(). There are also controls like MotionController, Swipe, Swiper, Parallax, Physics, etc. that provide interactivity. We look at these in ◎ Your Guide to Controling the Canvas with JavaScript.

Dragging on the Canvas

One-line drag and drop is fantastic! In the dawn of HTML 5, we kid you not, there was an 1800 character drag and drop script with lines that went off the screen. Of course, jQuery came along to help. On the canvas, we have ZIM.

new Circle().center().drag();
new Tile().center().drag();
The child of a container being dragged by default
new Tile().center().drag({all:true});
The whole container dragged with all:true
Parameters of ZIM drag()
new Circle().center().drag({
boundary:new Boundary(0,0,stageW,stageH)
});
// the circle can be dragged half way off the stage
// because the boundary contains the registration point
// which for a circle is in the middle
The circle can be dragged half way off the stage
new Circle().center().drag({
boundary:stage
});
// the circle stays fully on the stage
// or within any Display Object specified
The circle can be dragged to the edge of the stage
new Tile(new Circle(50, yellow, dark, 10))
.center()
.drag(); // the dragged object is on top
The dragged object is on top by default
new Tile(new Circle(50, yellow, dark, 10))
.center()
.drag({onTop:false}); // not on top
The dragged object is not on top with onTop:false

Gestures on the Canvas

Pinch, Pan and Rotate are common mobile gestures. ZIM provides support for this with the gesture() method. Try this on a multitouch screen or see https://zimjs.com/gesture. Parameters are available to choose which gestures to use as well as to set a boundary.

new Rectangle(300,300).center().gesture();

Transforming on the Canvas

PhotoShop has transformation tools with little handles to let you scale, move, stretch and rotate an object. ZIM has these as well with the transform() method. This is amazing! It means that people using your app on the canvas can transform objects. This is very empowering for things like meme makers, collage tools, planning apps, etc. CLEAR and TEST this:

new Rectangle(300,300, green)
.center()
.transform();
ZIM transform() method with larger handles for demonstration
A transformed rectangle :: pressing off the rectangle hides transforms
const rect = new Rectangle(300,300, green)
.center()
.transform();
// pass a reference to the object to remember
// or pass in an array of objects
// then pass a string for the persist id
new TransformManager(rect, "medium");

With one line of code the user transforms are saved

There is also the ZIM Layer() class which handles nested transforms.

ZIM Layer() class for nested transforms

Hit Tests and Conditionals

As you drag something or when you drop it, you may want to find out if that something is hitting something else. We call this a hitTest. We use a conditional to do the test in some event function. We might in general want to see if things are hitting and we usually use a ZIM Ticker for that.

ZIM Tips for HitTests
const circle = new Circle(100, red).center();const rect = new Rectangle().loc(100,100).drag();

const score = new Label(0).sca(2).pos(100,100,RIGHT);

rect.on("pressmove", ()=>{
if (rect.hitTestBounds(circle)) {
score.text = Number(score.text) + 1;
stage.update();
}
});
HitTestBounds and conditional to test if rectangle hits circle
Rectangle hitting bounds of circle — boo
const circle = new Circle(100, red).center();const rect = new Rectangle().loc(100,100).drag();

const score = new Label(0).sca(2).pos(100,100,RIGHT);

Ticker.add(()=>{
if (rect.hitTestCircle(circle)) {
score.text = Number(score.text) + 1;
stage.update();
}
});
Hit test in a Ticker with hitTestCircle() is not hitting — yay!

hitTestCircle()

tests any shape against points on a circle

Testing if two odd shapes are hitting one another is too processor intensive. We can, however, test if a point is hitting an odd shape. So what we can do to test an odd shape against a rectangle or circle is put points around the rectangle or circle and test the shape against each of these points.

Ticker.add(()=>{
if (circle.hitTestCircleRect(rect)) {
score.text = Number(score.text) + 1;
} else {
score.text = Number(score.text) - 1;
}
stage.update();
});
The ZIM hit tests in the ZIM Docs under Methods > Hit Tests

Last Words on Conditionals

In the code above, we have thrown in an if () {} else {} statement. This would reduce the score unless you are hitting the object. Wow… we would just have to make the circle move and we have a game! You will have to read ◎ Your Guide to Animation on the Canvas with JavaScript.

if (rect) {} // does rect hold an object?if (x > 1) {} // a greater than comparison operator if (x <= 20) {} // a less than or equal comparison operator // we can use && (and) and || (or)
// and note that the equality comparison operator
// is a double equal == not a single equal =
// the single = is the assignment operator (different)
if (a == "hello" && b == "bye") {} // we can test for negativesif (a != "hello") {}
if (!rect) {}

CONCLUSION

This has been a guide on special interactivity. That is to say, interactivity beyond the traditional events found in ◎ Your Guide to Components on the Canvas with JavaScript but not as far as the controls found in ◎ Your Guide to Controling the Canvas with JavaScript.

Further Reading

Interactive Media tends towards Creation, Web sites tend towards Consumption

Inventor, Founder of ZIM JavaScript Canvas Framework and Nodism, Professor of Interactive Media at Sheridan, Canadian New Media Awards Programmer and Educator

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store