YOUR GUIDE TO

Responsive and Adaptive Design on the Canvas

These canvas controls will help make your app just right!

Welcome readers from ◎ Your Guide to Coding Creativity on the Canvas

It has been about ten years… have you settled on a definition for responsive and adaptive design? On the face of it, the two words mean the same thing. What really matters is that we care about the user and their environment. Responsive could be scaling or wrapping and adaptive could be layout or feature change based on environment. Regardless, we can deal with it on the canvas.

Image for post
ZIM Pages demo with responsive and adaptive design on the canvas

Basic Responsive Design on the Canvas

Techniques for responsive design include scaling, positioning and wrapping on window resize. Let’s look at the basics first and then look at controls to automate complexities.

We will be using the ZIM JavaScript Canvas Framework. For alternatives, please see ◎ Your Guide to Selecting a JavaScript Canvas Library or Framework. For more information on the templates below see ◎ Your Guide to Setting up an Editor and Template to Code on the Canvas.

In ZIM, we have a Frame() which sets up our canvas. The first parameter is the scaling mode which affects our responsive design as follows:

  1. FIT: scales width and height (proportionally) to fit in the window.
  2. OUTSIDE: scales width and height to fit outside the window.
  3. FULL: makes canvas the window size with no scaling.
  4. TAG: scales the canvas to an HTML tag (with fit or full).
Image for post
ZIM Frame page with options for template
const frame = new Frame("fit", 1024, 768); // fit mode // ORconst frame = new Frame(); // full mode by default

Fit is the easiest to code because you have dimensions to work with and the whole app just scales. Most of the ZIM Web examples and exercises in these guides use the fit mode. However, fit is not best for mobile as it will likely leave unused space at the sides.

For mobile, we use the full scaling mode of the Frame

SCALING AND POSITIONING ON THE CANVAS

Scaling and positioning can be done in percentage of the window (stage width and stage height) and can have minimums and maximums set.

  • In HTML and CSS there are percent units.
  • In programming there are fractions or ratios.

We scale and position when the window changes size. This can be captured with a Frame resize event. We would use the full scaling mode and base our manual scaling on the frame width and height which we tend to save as stageW and stageH in the template.

Below, we scale a circle to 20% the stage using the ZIM scaleTo() which can scale to a percentage of any container. It has parameters to scale to the width, height, both, fit and outside. See the ZIM docs for scaleTo(). We also position the circle so its edges are 10% away from the top left corner by multiplying the stageW and stageH by .1 which is 10%.

const frame = new Frame();
frame.on("ready", ()=>{
let stageW = frame.width;
let stageH = frame.height;

const circle = new Circle();

frame.on("resize", ()=>{
// get new width and height
stageW = frame.width;
stageH = frame.height;

// scale and position content
circle
.scaleTo(stage, 20)
.pos(stageW * .1, stageH * .1);
});
}); // end ready

Please visit the Responsive Canvas with ZIM CodePen below. We did not embed the pen because you need to stretch it in the window to see the responsive effects.

We can also apply minimum and maximum values using the constrain() function in ZIM which is just a double conditional bounds check. See the ZIM Docs for constrain(). Please visit the Responsive Canvas 2 with ZIM CodePen to try it out.

Image for post
Responsive Canvas 2 with ZIM showing min and max scale

GRIDS AND GUIDES

ZIM has Grid() and and Guide() classes to help place objects on the stage using percentage (or toggle to pixels with the P key). These are controls. We look at more controls later on in this guide.

new Grid();
new Guide({vertical:false}); // horizontal Guide
Grids and Guides in ZIM (older code using zim namespace which is no longer needed)

WRAPPING ON THE CANVAS

Text can be wrapped on the canvas using a Label() with the labelWidth parameter and property that can be set in a resize event.

Usually, we do not wrap text as is common in traditional HTML but rather design text to fit regions and then scale and position the regions as will be seen with the Layout class.

For wrapping objects other than text, ZIM has the Wrapper() class which is much like a CSS FlexBox with the following features:

  • alignment for each column and whole rows
  • spacing, spread, stretch or column types
  • flip, reverse, bottomFull, and col/row void settings
  • margins on objects that do not affect other objects
Image for post
ZIM Wrapper() class :: similar to the CSS FlexBox

Here is a simple example with the objects to wrap, the start width and horizontal and vertical spacing. See the ZIM Docs for Wrapper for many more options. We then resize() the wrapper in an interval.

var circles = [];
loop(40, function () {
circles.push(new Circle(20, [orange, green, blue]));
});
var wrapper = new Wrapper(circles, 400, 20, 20).center();
interval(.5, function () {
wrapper.resize(rand(300,500)).outline();
stage.update();
});
Image for post
Wrapper on the Canvas

Wrapper can also be added to ZIM Window() which can be set to have a resize handle and full browser window controls. Wrapper can also be added to the ZIM Layout() class to wrap within regions.

Responsive and Adaptive Canvas Controls

Handling responsive and adaptive design can get tricky when you want to scale multiple adjacent regions with different percents, margins, minimum and maximums. ZIM provides controls to help.

Controls operate on existing content. We explore other controls in ◎ Your Guide to Controlling the Canvas with JavaScript.

Image for post
Page and layout controls for the canvas

The Wrapper class above is also a control that was very complex to code. You do not want to do that type of code manually.

Along with the Wrapper, ZIM provides two main responsive design controls: the Tile() class and the Layout() class. ZIM also provides a system for adaptive design with the Pages() class.

TILE

Tile is used to make art by cloning objects in a grid but it can also be used to layout content much like a table in HTML. See the unique parameter in the ZIM Docs, new to ZIM Cat. Tile is more flexible than a table, allowing for rows to have their own column spacing, but content is still locked into rows and columns. Tile features:

  • cloned or unique content
  • columns and rows
  • spacing and alignment
  • spreading and squeezing
  • optional individual column widths
  • horizontal and vertical mirroring
YouTube video for responsive Tile in ZIM

LAYOUT

ZIM has a Layout() class to handle Flexive Design. Flexive Design is when regions with set aspect ration are scaled in relation to one another. This was termed back in the days of Adobe Flash and Adobe Flex (given to Apache). Adobe, a large player in the WWW Consortium, most likely helped guide development of the CSS FlexBox.

Image for post
Flexive Design (2014) in Adobe Flash and Flex applications
YouTube video for Layout Class in ZIM (old ZIM but same principles)

With the Layout() class you specify regions to layout. These can be resized to fit the window size. Down below is a quick example of a vertical layout. The Layout class features:

  • a holder for the layout (any Container)
  • an array of regions to layout (any DisplayObject)
  • region objects with percentages
  • margins, max and mins, aligns
  • background colors
  • vertical or horizontal layouts
  • bounds to view regions
  • scaling object for layout (default stage)
// these would be containers with your content
// make sure that bounds are set on containers
const header = new Rectangle(500, 200, blue);
const content = new Rectangle(600, 500, green);
const footer = new Rectangle(500, 200, blue);
stage.addChild(header, content, footer);

// make the Layout
const layout = new Layout({
holder:stage,
regions:[
{object:header, marginTop:5, maxWidth:80, minHeight:10},
{object:content, marginTop:5, maxWidth:90},
{object:footer, marginTop:5, maxWidth:80, height:10}
],
lastMargin:5
});
// using a manager lets you resize all layouts at once
// otherwise you could resize() each layout individually
const manager = new LayoutManager();
manager.add(layout);

frame.on("resize", () => {
manager.resize();
stage.update();
});
Image for post
Quick example of laying out vertical regions on the canvas

PAGES

ZIM has a Pages() class which lets you set up a series of pages and swipe between them. Traditionally, the pages were Container() objects, but in ZIM Cat, we introduced the Page() class along with some really cool particle emitter transitions!

Image for post
Swiping between pages on the canvas
// for responsive design, these pages would hold Layout objects
const pH1 = new Page(stageW, stageH, green, yellow);
const pH2 = new Page(stageW, stageH, orange, red);
// the Pages object sets up swiping between pages
// for button interaction use the go() method
const pagesH = new Pages([
{page:pH1, swipe:[pH2, pH2]},
{page:pH2, swipe:[pH1, pH1]},
], "bubbleZIM", .7).center();

The Pages() class controls what pages are on the stage. For adaptive design, we make a Pages object for vertical (portrait) pages and a Pages object fro horizontal (landscape) pages. We capture the orientation event and then swap the pages objects.

For adaptive, we swap the pages objects!

frame.on("orientation", () => {
if (frame.orientation == "horizontal") {
// will want to match current page with the go() method
hPages.addTo().enable();
vPages.removeFrom().disable();
} else {
vPages.addTo().enable();
hPages.removeFrom().disable();
}
});

You can branch pages so if you have a Pages object with a set of horizontal pages and you swipe vertically, it takes you to another Pages object with a different set of pages for the horizontal swipes.

MANAGERS

Like Layout objects, Pages objects need to be resized in the Frame resize event. Pages, Layout, Grid and Guide all have their own managers but it is easier to add them to a single ResizeManager() object and resize the manager to resize everything. Wow!

const manager = new ResizeManager();
manager.add([pages, layout, grid, guide]);
frame.on("resize", () => {
manager.resize();
});

CONCLUSION

Image for post
ZIM Model View Controller demo with responsive and adaptive design on the canvas

Working on the canvas is usually more structure and less flow. We tend to work with fixed-aspect regions where game-play or interfaces may scale but not stretch. The ZIM Layout() class in a full scaling mode handles these situations.

Sometimes the exact bounds are not important in which case the outside scaling mode may be an option. An example might be making certain types of generative art. The fit scaling mode is often a convenient choice for Web apps.

In this guide we went through the basics of responsive design with scaling and positioning based on a percentage or ratio. We looked at wrapping, tiling and layout. We considered the Pages class for responsive design, although you can add, remove and adjust anything with code based on whatever input makes sense to help people engage with your art, game, app, etc.

At ZIM, we call them Zapps!

Further reading

The canvas is a great place to code creativity. Please read ◎ Your Guide to Coding Creativity on the Canvas which is an overall guide with links to individual guides of which this guide is a part.

A good place to go next would be ◎ Your Guide to Controling the Canvas with JavaScript where we take a look at the rest of the controls!

All the best! Dr Abstract.

Image for post

Follow us on Twitter at ZIM Learn and here is ZIM Learn on YouTube!

Written by

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