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

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

Basic Responsive Design on the Canvas

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
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

  • 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
Image for post
Responsive Canvas 2 with ZIM showing min and max scale

GRIDS AND GUIDES

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

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
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
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

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

Image for post
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

  • 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

Image for post
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
Image for post
Quick example of laying out vertical regions on the canvas

PAGES

Image for post
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

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

CONCLUSION

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

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
Image for post

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

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