YOUR GUIDE TO

Style on the Canvas

Dr Abstract is no stranger to style, nor is the Canvas!

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

Image for post
Image for post

Dr Abstract coded CSS-like style on the canvas in a single day and was surprised that it was merely fifty lines of code! Of course, for you to use styles on the canvas, it is as easy as CSS. Let’s take a look at styles on the canvas and then we will explain the story behind the code.

Any parameter can be used as a style!

You can code along with this Online Editor. Copy or type this and TEST:

STYLE = {width:500, corner:0};
new Button().center();

Note the commas after the styles, not semi-colons, and units are not required (nor are they missed). You may think this format comes from CSS but really it is the other way around. Object literals were in programming before CSS and used for the same reason, to set properties of objects.

Image for post
Image for post

We are using the ZIM JavaScript Canvas Framework. For alternatives, please see ◎ Your Guide to Selecting a JavaScript Canvas Library or Framework. We don’t think you will find styles in other libraries. Also, please note, that the styles are on the ZIM DisplayObjects. ZIM also has styles added to controls since the time of the video below.

Image for post
Image for post

TYPES AND GROUPS (like CSS selectors)

The earlier code example, would apply a width of 500 and corner of 0 to all display objects made afterwards. We can set a type of Button to apply styles specifically to all buttons. We will also center the button (and add it to the stage) with the center style:

STYLE = {
type:{
Button:{width:500, corner:0, center:true}
}
};
// or with the Style Class directlyStyle.addType("Button", {width:500, corner:0, center:true});new Button();

To apply styles to a group of objects use group which is like a class in CSS. CLEAR your code and copy or type this:

STYLE = {
group:{
big:{scale:2}
}
};
// or with the Style Class directlyStyle.addGroup("big", {scale:2});new Slider({group:"big"}).pos(0,100,CENTER);
new Dial({group:"big"}).center();
Image for post
Image for post

CASCADING

Group styles override type styles which override general styles. All these are overridden by parameters passed directly to the object.

STYLE = {
color:pink,
type:{
Circle:{color:blue}, // these override pink
Rectangle:{color:blue}
},
group:{
lemon:{color:yellow}
},
center:true,
mov:series(-300,-100,100,300),
borderColor:dark,
borderWidth:2
};
new Rectangle(); // blue
new Circle({group:"lemon"}); // overrides blue
new Triangle({color:green}); // overrides pink
new Poly(); // pink
Image for post
Image for post

DYNAMIC STYLES

ZIM has dynamic parameters called ZIM VEE values. Please see ◎ Your Guide to Conveniences when Coding on the Canvas. All styles can use ZIM VEE values. We saw an example of a series above to spread the objects out with the mov (or move) style. Here are some examples. Please code along with us!

Pick Literal formats:
[1,3,2] — random;
{min:10, max:20} — range;
series(1,2,3) — order,
function(){return result;} — function

STYLE = {
color:[red, green, blue], // pick randomly
center:true,
move:series(-400,-200,0,200,400), // pick in series
}
loop(5, ()=>{ // make five rectangles
new Rectangle();
});
Image for post
Image for post

Add a range to the scaleY of the rectangles. If a Rectangle has no width specified it will match the height to make a square so we set a width too:

width:100,
height:{min:100, max:400}, // pick a range
Image for post
Image for post

Add an alternating border color and have the border width depend on the result of a function. In this case, we use the JavaScript ternary operator so that the border is 5 pixels in the morning and 10 pixels at night.

function getBorder() {
return new Date().getHours() < 12 ? 5 : 10;
}
STYLE = {
color:[red, green, blue],
width:100,
height:{min:100, max:400},
center:true,
move:series(-400,-200,0,200,400),
borderColor:series(white,black),
borderWidth:getBorder // use result of function
}
loop(5, ()=>{
new Rectangle();
});
Image for post
Image for post

Sometimes we do not want to use ZIM VEE. For instance, when setting a corner to an array so it uses the four values per corner. So then use noPick:

STYLE = {
corner:{noPick:[50,0,50,0]}
}
new Button().center();
Image for post
Image for post

Sometimes objects clone other objects like Tile and Emitter. In this case, we can use the delayPick style to bypass the object being cloned and have the style applied to the final cloned object. We may also want to stop an object from receiving styles. In the case below, we use a general scale style. This would normally scale the Tile and the Circle objects in the tile! So we have turned off style for the tile. We could have applied the scale style to the type Circle or Tile as an alternative.

STYLE = {
color:[red, green, blue],
delayPick:true,
borderColor:dark,
dashed:true,
scale:2
}
new Tile({style:false}).center();
Image for post
Image for post

TRANSFORMS, CONVENIENCES, METHODS AND INHERITANCE

Along with styling general parameters, there are transformation styles, method styles and general convenience styles.

The following transformations can be applied as styles:
x, y, rotation, alpha, scale, scaleX, scaleY, regX, regY, skewX, skewY

The following methods can be applied as styles:
addTo, loc, pos, center, centerReg, transform, drag, gesture,
outline, bounds, mov, animate, wiggle and expand

The following conveniences can be applied as styles:
visible, add, move, style

A value of ignore can be provided to any style to ignore previous settings.

Objects can INHERIT styles from their parent. For example, setting a font color property on List() will pass that to Tabs() which pass it to Button() which passes it to Label(). The inherit parameter of an object can receive an object literal of styles to be inherited.

STYLE CLASS

STYLE was launched in ZIM OCT (version 8). At the time, we made styles with STYLE and if we wanted to change the styles we were applying then we would modify the STYLE constant. Here are some examples just to demonstrate what can be done.

We would not usually code this way because if styles are used only once, then there is no point in using them. We would just put the color in as a parameter.

STYLE = {color:red};new Circle().center(); // red circle STYLE = {}; // turn off the stylenew Circle().pos(100,100); // black STYLE = {color:green};new Circle().pos(100,100,RIGHT); // greenSTYLE.type = {Circle:{color:blue}};new Circle().pos(100,100,RIGHT,BOTTOM); // blue
new Rectangle().pos(100,100,LEFT,BOTTOM); // green
STYLE.type.Circle.color = yellow;
STYLE.type.Circle.scale = .5;
new Circle().center(); // yellow and smaller
Image for post
Image for post

This worked fine but was a little informal. So in ZIM Cat, we introduced an alternative way to manage styles, using the Style class. We use static methods right on the Style class to add, adjust, remember, remove, etc. the styles. See the ZIM Docs on STYLE for a complete list of functionality. Here is the above example, using Style:

It is up to you if you want to use some or all of either STYLE or Style.

Style.add({color:red});new Circle().center(); // red circle Style.clear(); // turn off the stylenew Circle().pos(100,100); // black Style.add({color:green});new Circle().pos(100,100,RIGHT); // greenStyle.addType("Circle", {color:blue});new Circle().pos(100,100,RIGHT,BOTTOM); // blue
new Rectangle().pos(100,100,LEFT,BOTTOM); // green
// this will not delete other styles for the type
// but will overwrite any of the same type of styles
Style.addType("Circle", {
color:yellow,
scale:.5
});
new Circle().center(); // yellow and smaller
Image for post
Image for post

Coding STYLE on the Canvas — the Story

Image for post
Image for post

We could not believe it when we coded CSS-like style on the canvas in a single day. The reason for the short time was that ZIM was already using configuration objects as an option/alternative for traditional parameters. So it was just a matter of abstracting the object literals and applying them generally. The cascading aspect was accomplished in the code above by merging and cloning various object literals to handle groups, types, general and specific styles.

We were able to efficiently integrate styles throughout ZIM. This was done in a couple places for each Display Object. Here is an example:

// near the top var DS = style===false?{}:zim.getStyle("Button", group, inherit);if (width==null) width=DS.width!=null?DS.width:200;// near the bottomif (style!==false) zim.styleTransforms(this, DS);

DS gets the styles that have been filtered through the cascading code. We then apply any styles if there is no parameter value. We added a bit near the end to apply the transformations. The transformation code was not included in the rotated image of the code above. It was straight-forward code but also dealt with ZIM VEE values so it was about twice as much as the core code for styles.

The styleTransform() ZIM function was added in ZIM Cat so that creators can make classes and use ZIM STYLE on their objects. See the ZIM Docs on STYLE.

Differences Between CSS and Canvas Styles

The HTML canvas can only have CSS applied to the whole tag and not its parts. We have added CSS-like styles to the Display Objects in ZIM. Below are some of the differences between the two systems.

  1. A main difference is that the styles on the canvas do not affect objects that are already made but only objects made after the style is set.
  2. The canvas uses commas and not semi-colons.
  3. There are no units on the canvas as the unit is pixels.
  4. There is a difference in the selectors where ZIM uses type and group collections of either class names for types or string names for groups.
  5. Canvas selectors do not have pseudo-classes, like hover. Hover is handled with rollColor, rollBackgroundColor, etc.
  6. Canvas styles have dynamic parameters: random/series/range/function which are very handy and more versatile than n-th child of CSS.
  7. Being JavaScript based, variables are no problem on the canvas.

CONCLUSION

We have been working with styles on the canvas for a few years and they have certainly been handy. Canvas objects are made with code which means we can often use loops and may need styles less frequently. Some apps use STYLE extensively, for instance the ZIM Synth.

Image for post
Image for post

Further reading

The canvas is a great place to code creativity. Please read ◎ Your Guide to Coding Creativity on the Canvas if you have not yet. This overall guide has links to the individual guides of which this guide is a part.

We would be happy to answer any questions here or on the ZIM Slack channel. We hope you made the most out of the guide and coded along with us. If not, come back when you have time and give it a go!

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!

Written by

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

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