"Hello, World!" - using Scrawl in a web page

Extensions: core, phrase

The obligatory 'Hello, World!' example

<!DOCTYPE html>

    <title>Hello, World</title>

    <canvas id="mycanvas" width="400" height="200">
      <p>It looks like your browser doesn't support the <canvas> element.</p>
    <script src="path/to/scrawlCore-min.js"></script>
      var mycode = function() {
        'use strict';

        //define Phrase entity
          text: 'Hello, Scrawl World!',
          startX: 'center',
          startY: 'center',
          handleX: 'center',
          handleY: 'center',
          font: '30pt serif'

        //update the canvas display

      //load extensions; initialize and run code
        path: 'path/to/minified/extensions/folder/',
        extensions: ['phrase'],
        callback: function() {
          window.addEventListener('load', function() {

            //initialize scrawl object

            //run canvas code
          }, false);
  1. Load the core using <script src="path/to/scrawlCore-min.js"></script>
  2. Load additional extensions using scrawl.loadExtensions()
  3. When extensions have loaded, the callback function will run
  4. Initialize Scrawl using scrawl.init()
  5. Create a Phrase entity using scrawl.makePhrase()
  6. Render the canvas using scrawl.render()

The scrawl.init() function

The scrawl.init() function needs to be run once the web page has loaded. This function builds the Scrawl library and imports any <canvas> elements it finds on the web page into it. The first canvas will be set as the current canvas and any entitys or other Scrawl-related objects subsequently created will automatically be assigned to that canvas.

The canvas elements themselves can be styled and positioned on the page using CSS and POJ (plain old JavaScript). Warning: never set the width or height of a canvas element using CSS styling - CSS will stretch or shrink the canvas to fit the new dimensions, rather than change the size of the canvas's drawing context.

Scrawl entitys

Scrawl supports a range of different entity types - such as the Phrase entity, which displays text on a canvas. Entitys are created using various factory functions, each of which take a single argument object. The positioning and styling of an entity can be set at the time of its creation by setting the attributes of the argument object to appropriate values.

Rendering canvas elements

Scrawl takes a flexible approach to rendering canvas scenes, with a number of functions available to clear, compile and display canvases. scrawl.render() is the simplest such function, which causes all canvases on a page to update and display the entitys associated with them.

Importing a canvas into the Scrawl library

Adding a canvas element to a page after it has loaded

Scrawl can add a canvas to a web page at any time by using the scrawl.addCanvasToPage() factory function. When called with no argument object the new canvas will be given a width of 300px and a height of 150px, and added to the end of the web page.

The .makeCurrent() function - which takes no arguments - ensures that the entitys created in the following lines are assigned to the new canvas element.

Adding a Scrawl.js canvas to a page programmatically (1)

scrawl.addCanvasToPage() can take an object argument with the following key attributes:

  • canvasName String - the new canvas element's unique identifier (default: computer generated)
  • width Number - the required width of the new canvas (default: 300)
  • height Number - the required height of the new canvas (default: 150)
  • parentElement DOM object, or String - the DOM element, or that element's id value, to which the new canvas will be appended (default: document.body)

Giving your canvas a unique name (#id) is strongly recommended, as it makes styling and positioning the canvas (through CSS, jQuery, etc) a lot easier. Scrawl will assign the new canvas element an id attribute when it is created, but the computer-generated id is not predictable.

Adding a Scrawl.js canvas to a page programmatically (2)

Scrawl extensions

Extensions: core

Scrawl has an extensions-based design; a web page only needs to download and run the core module and any Scrawl extensions necessary to run the canvases on the page.

Getting the Scrawl-canvas JavaScript library extensions

The Scrawl-canvas JavaScript extensions (which come in both source and minified versions) can be downloaded from GitHub - github.com/KaliedaRik/Scrawl-canvas, or directly from this link: scrawl.rikweb.org.uk/downloads/scrawl-canvas_6-0-1.zip.

Scrawl (experimentally) supports Bower downloads using the package name scrawl-canvas.

Once downloaded, save the extensions folder on your web server (or development environment) in a place where web pages can access them.

Please do not directly link your code to the Scrawl files on this website. I cannot afford to pay for the bandwidth!

Core module

Every web page using Scrawl must include the core module. This module needs to be fully loaded by the browser before any support extensions can be added to it. The minified version of the current core module (scrawlCore-min.js, version 6.0.1) is 80kb in size - and considerably less when gzipped.

Include the Scrawl library in a webpage

<!DOCTYPE html>
  <!-- web page code goes here -->

  <script src="path/to/scrawlCore-min.js"></script>

    //Scrawl JavaScript code goes here

Support extensions

Support extensions add functionality to the core module. These extensions have no dependencies beyond their need for the core module to be preloaded, so the order in which they are loaded is not important. Support extensions include:

  • scrawlBlock-min.js (5kb; alias: block) - adds Block (square and rectangular) entitys to the core
  • scrawlWheel-min.js (7kb; alias: wheel) - adds Wheel (circle, wedge) entitys to the core
  • scrawlPhrase-min.js (13kb; alias: phrase) - adds Phrase (single line and multiline text) entitys to the core
  • scrawlImages-min.js (40kb; alias: images) - adds image handling functionality, including Picture entitys and Pattern design objects, to the core
  • scrawlPath-min.js (24kb; alias: path) - adds Path entitys to the core - these can be used to position other entitys
  • scrawlShape-min.js (9kb; alias: shape) - adds Shape (simple, path-based) entitys to the core
  • scrawlPathFactories-min.js (9kb; alias: factories) - adds a set of factory functions to the core, for the production of regularly shaped (triangle, star, ellipse, rounded-corner rectangles, etc) Path and Shape entitys
  • scrawlFrame-min.js (20kb; alias: frame) - adds 3d emulation to the 2d canvas element

Additional extensions add functionality to Scrawl entitys:

  • scrawlAnimation-min.js (28kb; alias: animation) - adds animation functionality - including tweens and timelines - to the core
  • scrawlCollisions-min.js (11kb; alias: collisions) - adds collision detection functionality to the core
  • scrawlColor-min.js (18kb; alias: color) - adds a color object to the core
  • scrawlFilters-min.js (25kb; alias: filters) - adds a set of filter functions to the core
  • scrawlStacks-min.js (50kb; alias: stacks) - adds the ability to manipulate and animate <canvas> and other DOM elements within a 3d space

A couple of experimental extensions are also included:

  • scrawlPhysics-min.js (10kb; alias: physics) - adds a physics engine to the core
  • scrawlSaveLoad-min.js (9kb; alias: saveload) - adds the ability to save Scrawl objects as JSON strings, and load those strings into a <canvas> element

Loading extensions synchronously

Extensions can be loaded in the normal way, and in any order, once the core module has been loaded:

Synchronously load Scrawl extensions

<!DOCTYPE html>
  <!-- web page code goes here -->

  <script src="path/to/scrawlCore-min.js"></script>
  <script src="path/to/scrawlBlock-min.js"></script>
  <script src="path/to/scrawlAnimation-min.js"></script>
  <script src="path/to/scrawlWheel-min.js"></script>

    //Scrawl JavaScript code goes here

Loading extensions asynchronously

Scrawl extensions can be loaded asynchronously using the scrawl.loadExtensions() function. All the pages on this website use this method.

The loadExtensions() function takes an array of extensions alias strings and, where supported by the browser, sends out asynchronous requests for each file. If the browser doesn't support asynchronous loading of JavaScript files, they will be loaded synchronously in the normal manner.

The function also accepts an anonymous callback function, which will only be run once all the required extensions have fully loaded.

Asynchronously load Scrawl extensions

<!DOCTYPE html>
  <!-- web page code goes here -->

  <script src="path/to/scrawlCore-min.js"></script>
    var mycode = function(){
      //Scrawl JavaScript code goes here
      path: 'path/to/extensions/',
      extensions: ['block', 'animation', 'wheel'],
      callback: function(){
        window.addEventListener('load', function(){
        }, false);

Combining extensions into a single document

To combine Scrawl extensions into a single document, copy the core module (scrawlCore.js or scrawlCore-min.js) file into a new text file, then add the required support extensions files (in any order) beneath the core file text.

Do not mix source and minified versions of extensions in the document - bad things may happen.

The Scrawl library

Extensions: core

The Scrawl library is a big object - called scrawl - which stores all the various objects, arrays and factory functions created by Scrawl during its operations. Objects and functions can easily be accessed via the library as-and-when required, both by Scrawl code and any other JavaScript code running at the same time (and on the same web page) as Scrawl.

The library also includes direct references to DOM elements wrapped by Scrawl objects. The links can be used for JavaScript operations on these elements beyond Scrawl's scope - such as styling or adding event listeners to <canvas> elements:

Library sections

To help navigate the library, Scrawl breaks it into sections. The following sections are set up by the core module:

  • scrawl.pad.CANVASID - Pad controller object for each visible <canvas> element
  • scrawl.canvas.CANVASID - reference to the DOM <canvas> element; can be used instead of document.getElementById('CANVASID')
  • scrawl.context.CANVASID - reference to the DOM <canvas> element's 2d context engine; can be used to draw directly on the canvas using native JavaScript Canvas API functions
  • scrawl.cell.CELLNAME - Cell wrapper for all canvases, including non-visible ones
  • scrawl.group.GROUPNAME - Scrawl Group objects
  • scrawl.design.DESIGNNAME - Scrawl design objects (Gradient, RadialGradient, Pattern, Color)
  • scrawl.entity.ENTITYNAME - Scrawl entity objects (Block, Wheel, Phrase, Picture, Path, Shape)

Every object created by Scrawl can be given a name as part of the object's factory function creation process. These names should be unique - if no name attribute is supplied in the argument object, or if the name already exists for another object, then Scrawl will generate a random name for the new object.

Scrawl Pad objects will be named after the id or name attribute given to their <canvas> element

Utility functions

Scrawl includes a number of utility functions for manipulating JavaScript Arrays, Numbers and Objects:

  • scrawl.mergeInto(old, new) - adds the attributes of the new object to those of the old object, where those attributes don't already exist in the old object. Returns the amended old object
  • scrawl.mergeOver(old, new) - adds the attributes of the new object to those of the old object, where those attributes don't already exist in the old object, and replaces the values of existing attributes with new values. Returns the amended old object
  • scrawl.contains(array, value) - returns true if the given value is present in the array; false otherwise
  • scrawl.pushUnique(array, value) - adds the value to the array if it does not already exist in the array. Returns the amended array
  • scrawl.removeItem(myarray, value) - removes a value from the array. Returns the amended array
  • scrawl.isBetween(number, minimum, maximum) - returns true if the number lies between (but does not equal) the minimum and maximum values
  • scrawl.isBetween(number, minimum, maximum, true) - returns true if the number lies between, or equals, the minimum and maximum values
  • scrawl.isa(variable, type) - returns true if the value is of the correct type. The types that can be tested for include:
    • 'str' - for Strings
    • 'num' - for Numbers
    • 'bool' - for Booleans
    • 'fn' - JavaScript Function objects
    • 'arr' - JavaScript Array objects
    • 'obj' - JavaScript (but not DOM) objects
    • 'date' - JavaScript Date objects
    • 'vector' - Scrawl Vector objects
    • 'quaternion' - Scrawl Quaternion objects
    • 'img' - DOM <img> elements
    • 'video' - DOM <video> elements
  • scrawl.xt(variable) - returns true if the variable exists (is NOT undefined); false otherwise
  • scrawl.xta(variable, variable ...) - returns true if all of the variables included in the argument list exist; false otherwise
  • scrawl.xto(variable, variable ...) - returns true if at least one of the variables included in the argument list exists; false otherwise
  • scrawl.xtGet(variable, variable ...) - returns the first variable in the argument list that exists; null otherwise
  • scrawl.xtGetTrue(variable, variable ...) - returns the first variable in the argument list that both exists and is true; null otherwise
  • scrawl.safeObject(variable) - checks to see if variable is a JavaScript object - if true, the variable is returned; if false, a blank object - {} - is returned

Scrawl library object documentation

For complete details of the core library's attributes and functions, check out the documentation: scrawl documentation.

Canvases, Pads and Cells

Extensions: core

For every visible <canvas> element in the web page that Scrawl discovers, or inserts into the web page's DOM, Scrawl will create a controller object known as a pad. We use pads to tell the browser what it should draw on a <canvas> element each time the screen is refreshed.

Scrawl also creates a wrapper object known as a cell for each visible <canvas> element. The cell associated with the visible canvas is called the display cell, and the name of the Cell object is kept in the Pad object's .display attribute.

Each pad will also create a second, invisible <canvas> element, which doesn't get added to the web page's DOM. This element is called the base cell and has its own cell object whose name is stored in the pad object's .base attribute.

Each time a pad renders a visible <canvas> element, it first tells the base cell to draw all the entitys associated with it onto its canvas element. Once the drawing stage is complete, the entire base canvas is copied over to the display canvas element in a single copy operation.

While this may seem like overkill, it does allow us to separate the rendering operation into discrete clear, compile and show operations, which can be tweaked to meet the needs of more complex scenes and animations.

The separation of actions is particularly useful when we start adding cells, each wrapping an additional hidden canvas element, to a pad. Additional cells can be thought of as layers, like those found in Photoshop or the Gimp, each with its own collection of transforms, entitys and gradients which together add up to make the final scene.

A pad's cell layers do not need to be of equal dimensions. Like entitys, they can be positioned and resized as required.

For more information on pads and cells, check out the Displaying scenes section of this tutorial.

Pad and Cell object documentation

For complete details of all pad and cell attributes, and their functionality, check out the documentation for these objects:

Scrawl naming conventions

Extensions: core

Much of the internal working of scrawl-canvas relies on the passing of object name attributes between functions. As a result, Scrawl works most effectively when objects created via the various factory functions are given unique .name attributes.

Acceptable name attributes need to follow these guidelines:

  • Use Strings, not Numbers or any other type of JavaScript object, for the name.
  • Make sure each name is unique - if Scrawl encounters a name that has already been assigned to another object, it will default to creating a randomly generated name for the new object.
  • Avoid using the following characters in the name, as Scrawl will automatically convert them to underscores: . / + * [ { ( ) ~ - # \ ^ $ | ?
  • For the same reason, don't use spaces in names.
  • Avoid using the = character in a name, as that is used in the names generated for Point and Link objects by Path entity factory functions.
  • Also for Path entitys, if you run into strange behaviour this may be due to using an _ underscore character in the entity's name; the general advice for now is to avoid using underscores in any names.
  • If you value your sanity, never use three consecutive underscores ___ in a name!

All names are case-sensitive - Scrawl will treat 'Mything', 'myThing'. 'MYTHING' and 'mything' as separate, unique names.

Core module documentation

For complete details of all Core module functionality:

Scrawl entitys

Extensions: core

Entitys are the workhorses of the Scrawl system. Each entity represents an object on the <canvas> display that can be positioned, styled, scaled and animated.

For convenience, Scrawl divides its entitys into six types:

  • Block entitys are simple rectangles
  • Picture entitys are also rectangles, used to display images, sprite sheet animations, image data from other cells, and videos
  • Phrase entitys display text, which can be broken across more than one line
  • Wheel entitys are simple circles, arcs and wedges
  • Shape entitys can be used to make lines, curves, regular shapes (such as triangles, pentangles, ellipses, rectangles with rounded corners, etc) and more complex shapes. They are similar to SVGTiny path elements.
  • Path entitys are like Shape entitys, but are constructed from sets of point and link objects. They can be used as frameworks for positioning other entitys, for example text along paths.

Each type of entity has its own factory functions for object creation. They also differ in the range of attributes and functionality they can perform, though all entitys share a common set of attributes and functions.

Core attributes:

  • .name string - unique identifier (default: computer generated)
  • .title string - title space (default: '')
  • .comment string - comment space (default: '')
  • .timestamp string - date and time of entity creation (default: computer generated)
  • .group string - name of group to which entity is (initially) assigned (default: current pad's base cell's group)
  • .order number - drawing order for entity (default: 0)
  • .visibility boolean - true for visible; false otherwise (default: true)
  • .method string - drawing method for entity (default: 'draw'||'fill', depending on entity type)

Entitys must be assigned to a Group when they are created. If no .group attribute is supplied, the factory function building the entity will assign it to the current pad object's base cell's Group.

The .order attribute is used to help determine the order in which entitys are 'stamped' onto their destination canvas. Entitys with higher .order values appear over those with lower .order values.

Entitys can be disabled (prevented from being stamped onto a canvas) by setting their .visibility attribute to false.

The .method attribute tells the entity how it is to stamp itself onto a canvas. There are a number of available drawing methods: 'draw', 'fill', 'drawFill', 'fillDraw', 'floatOver', 'sinkInto', 'clear', 'clearBackground', 'clip', 'none'. The following demo displays some of these methods:

Scrawl entitys: stamping methods


The stroke and fill styles tell the entity what colors they should use for their outlines and fills respectively. Both default to black. To use a gradient, pattern or Color object, set these attributes to the name of the desired object.

  • .strokeStyle string - CSS color string, or DESIGNNAME (default: '#000000')
  • .fillStyle string - CSS color string, or DESIGNNAME (default: '#000000')

The line styles tell entitys how to draw and join their outlines.

  • .lineWidth number - stroke outline width (default: 1)
  • .lineCap string - line cap shape - 'butt', 'round', 'square' (default: 'butt')
  • .lineJoin string - line join style - 'bevel', 'round', 'miter' (default: 'miter')
  • .miterLimit number (px) - maximum extent of mitre joins (default: 10)
  • .scaleOutline boolean - false to render stroke at given width, ignoring scale factor (default: true)

Scrawl supports dashed outlines - though only some browsers display dashed outlines at this time. Similarly, Shape and Path entitys support the 'evenodd' fill method in addition to the default 'nonzero' method.

  • .lineDash array of numbers - pattern for line dash eg [2,1,4,1] (default: [])
  • .lineDashOffset number - path offset for starting lineDash pattern - can be used for the marching ants animation effect (default: 0)
  • .winding string - fill method - 'nonzero', 'evenodd' (default: 'nonzero')

Every entity can be given a drop shadow - and some drawing methods ('floatOver', 'sinkInto') only work if the entity has been given a distinctive shadow.

  • .shadowOffsetX number (default: 0)
  • .shadowOffsetY number (default: 0)
  • .shadowColor string - CSS color (default: 'rgba(0,0,0,0)')
  • .shadowBlur number (px) (default: 0)

Composite operations are used to determine how a entity interacts with what has already been painted on the canvas. The default is 'source-over', which means that the entity will be painted in its entirety over what has already been painted on the canvas (which will only show through the entity if its .globalAlpha attribute has been set to less than 1).

  • .globalAlpha number - the transparency value for the entity (default: 1)
  • .globalCompositeOperation string - the composition method for the entity (default: 'source-over')

Other composite operations include: 'source-atop', 'source-in', 'source-out', 'destination-over', 'destination-atop', 'destination-in', 'destination-out', 'lighter', 'darker', 'copy', and 'xor'. A few of these are not supported by all browsers, and some may produce different results in different browsers:

Global composite operations

Getting, and updating, entity attributes

In common with other Scrawl objects, the value of any entity attribute can be accessed using the .get() function. Attribute values can also be read directly though, due to Scrawl's internal workings, the returned values may not be the values that you expect them to be.

Similarly, an entity's attributes can be set using the .set() function. This function takes a single argument - an object with attributes set to the new values. We do not recommend setting attribute values directly, as this will often bypass essential data manipulation and lead to buggy performance.

Scrawl .set() and .get() functions

//initialize a new Block entity, setting its attributes to given values
var myBlock, test;

myBlock = scrawl.makeBlock({
  name: 'redblock',
  startX: 50,
  startY: 'center',
  fillStyle: 'red',
  width: 150,
  height: 100,
  handleY: '50%'

//get attribute values
test = myBlock.get('startX');                       //test = 50
test = scrawl.entity.redblock.get('width');         //test = 150

//set attribute values
  width: 120,
  fillStyle: 'blue'

//get attribute values
test = myBlock.get('width');                        //test = 120
test = scrawl.entity.redblock.get('fillStyle');     //test = 'blue'

Positioning entitys

Extensions: core

To display an entity on a <canvas> element, it needs to be positioned on that canvas. There are three approaches to positioning: absolute positioning, and relative positioning, using the canvas as a frame of reference; and reference positioning using other objects as the reference origin.

Interactive Scrawl line graph: crime in Hackney, London

Absolute positioning

Entitys keep their positioning coordinates in a Vector object stored in the start attribute. Coordinates are measured in pixels from a <canvas> element's top left hand corner.

To make it easier to set and change this coordinate, coders can also use the following alias attributes:

  • .startX number (px) - horizontal coordinate (default: 0)
  • .startY number (px) - vertical coordinate (default: 0)

The start attribute actually represents a entity's rotation/reflection point - it is the point within (or outside) the entity, around which it can be flipped or rolled. The orientation and rotation of the entity are controlled by the following attributes:

  • .flipReverse boolean - causes the entity to be drawn back-to-front (default: false)
  • .flipUpend boolean - causes the entity to be drawn upside-down (default: false)
  • .roll number - angle for rotating entity, in degrees (default: 0)
The effects of .flipReverse and .flipUpend

Offseting entitys from their innate rotation/reflection point

Every type of entity has an innate position for its rotation/reflection point. Blocks, Pictures, Phrases, and some types of Shape and Path entitys use their top left hand corner as ground zero; Wheels and other entitys center themselves around this point instead.

However, the positioning of the rotation/reflection point within a entity is not fixed. It can be offset by the handle attribute (another Vector object), which supports the following alias attributes:

  • .handleX number (px) - horizontal offset from rotation/reflection point
  • .handleY number (px) - vertical offset from rotation/reflection point

For both start and handle attributes, values can be negative, or larger than the cell's dimensions.

Relative positioning

An entity's start attribute can accept String values in addition to Number values. These values also use the cell as a frame of reference but instead of measuring an absolute distance from the cell's top-left corner, they represent a value relative to the cell's current width and height - where '0%' is the cell's top and left borders and '100%' is the bottom and right borders.

The handle attribute can also accept String percentage values. For handles, though, the frame of reference is not the cell but rather the entity's own dimensions, where '0%' represents the entity's top and left borders and '100%' the bottom and right borders.

For both the start and handle attributes, the String percentage values can be negative, or extend beyond '100%'

String constants are also supported. In the horizontal, or x, plane 'left' represents '0%' and 'right' '100%. Similarly in the vertical (y) plane 'top' is an alias for '0%' and 'bottom' for '100%'. In both planes the value 'center' stands for '50%'

Entity offsets (handles)

Scaling an entity's relative size is controlled by the scale attribute, with values greater than 1 making the entity larger. Note that scaling only affects String values; Number values remain absolute:

  • .scale number - dimensions scaling factor (default: 1)
Scrawl animation - manipulating entity 'roll' and 'scale' attributes

Reference positioning

One of Scrawl's key strengths is the ability to position an entity relative to the position of another entity. This is achieved very easily, by setting the entity's pivot or path attribute to the name of another entity which is to act as the reference frame for our entity. Combined with handle offsets, this can offer the coder a quick way to build, and control, more complex scenes from component entitys.

The .pivot attribute tells the entity to use a Point object, or another entity's start coordinates - or even the mouse coordinates - as its own rotation/reflection point.

  • .pivot string - POINTNAME, ENTITYNAME, or 'mouse' (default: false)

The .path attributes are used when moving an entity along a Path entity's path. Paths are dealt with in more detail in the path animation section of this tutorial.

  • .path string - ENTITYNAME of Path entity to be used as path object (default: false)

Scrawl entitys follow a hierarchy when determining their positions on a cell, with the .pivot attribute taking precedence over the .path attribute, which in turn takes precedence over the .start coordinate values.

Pivot and path behaviour can be constrained to the vertical and horizontal planes by setting the lockX and lockY attributes respectively.

  • .lockX boolean - set to true to lock the entity's horizontal position to its start.x value
  • .lockY boolean - set to true to lock the entity's vertical position to its start.y value
Entity offsets (handles)

Block entitys

Extensions: block

Blocks can be created by calling the scrawl.makeBlock() factory function. A Block can also be cloned from another Block by calling the .clone() function on it.

Blocks are drawn from their top-left corner, whose coordinates are stored in its .start attribute vector. The coordinates of the bottom-right corner of the Block are relative to the top-left corner, with values stored in entity's width and height attributes.

Cloning a Scrawl Block entity

If the width and height attribute values are supplied as numbers, then the dimensions will be measured in pixels. If they are supplied as percentage strings then the dimensions will be calculated as a percentage of the canvas width and/or height.

Block object documentation

For complete details of all Block attributes, and its functionality, check out the documentation:

Wheel entitys

Extensions: wheel

Wheels can be created by calling the scrawl.makeWheel() factory function. A Wheel can also be cloned from another Wheel by calling the .clone() function on it.

By default, Wheels place their rotation/reflection (.start) point at the center of the entity. This can be adjusted by setting the .handle attribute to the required offset.

Wheels are more complex that Blocks; they have .startAngle and .endAngle attributes which measure out an arc: by default a Wheel object will draw a circle with startAngle=0 and endAngle=360. 0° is due east (pointing to the right) of the Wheel's start coordinates.

Wheel size is set by the .radius attribute. This attribute can accept a number value which represent px distances, or alternatively a percentage string value. That percentage is relative to the cell width (not height).

Wheels can also be instructed to include their center point (.includeCenter) in their drawing operations - this will create pie segments:

Animating a Wheel entity by manipulating its 'roll' attribute

Wheel object documentation

For complete details of all Wheel attributes, and its functionality, check out the documentation:

Phrase entitys

Extensions: phrase

Phrases can be created by calling the scrawl.makePhrase() factory function. A Phrase can also be cloned from another Phrase by calling the .clone() function on it.

Additional attributes for Phrase entitys include:

  • .text string - text to be displayed (default: '')
  • .textAlign string - horizontal alignment: 'start', 'left', 'center', 'right', 'end' (default: 'start')
  • .textBaseline string - vertical alignment: 'top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom' (default: 'alphabetic')
  • .font string - CSS shorthand font string (default: false)

The .textAlign attribute can be used to justify ('left', 'center', 'right') text in multiline Phrases. The .textBaseline attribute only affects text assigned to a Path entity path. To position a Phrase on the cell, use the .start and .handle attributes. Phrases can be rotated using the .roll attribute.

Phrase objects break down the font string into separate attributes. These can be set individually either as part of the factory function, or via the .set() function after the object has been created.

  • .style string - text style, eg: 'italic' (default: 'normal')
  • .variant string - text variant, eg: 'small-caps' (default: 'normal')
  • .weight string||number - text weight, eg: 'bold', 700 (default: 'normal')
  • .size number - text size (default: 12)
  • .metrics string - text metrics (default: 'pt')
  • .family string - font family (default: 'sans-serif')
'Hello' (I think) in Chinese

Multi-line text in a Phrase entity

Scrawl is able to display multiple lines of text in a Phrase entity. This is achieved by adding the escape code \n into the text at the appropriate places. It is essential to give explicit names to Phrase entitys that may - at some point - display multiline text.

The space between lines can be altered by setting the .lineHeight attribute.

Scrawl does not support letter spacing functionality at this time, though adding such functionality is on the list of things-to-do.

Multiple line Phrase entitys

In general, canvas-based text is subject to the limitations of the HTML canvas API. The text is rendered onto the <canvas> element as a graphic, thus it may often suffer from a lack of sharpness; nor can it be selected by the user, or parts of it copied and pasted to other areas of the web page (or beyond). Phrase entity text is also invisible to assistive technology devices and software. While some of these issues can be overcome by using the entity's .title and .comment attributes (with appropriate coding elsewhere to make sure the text is exposed to AT software), by far the best solution is to use normal HTML5 text-based elements to display the text, and incorporate them into the canvas display using scrawl stacks.

Phrase object documentation

For complete details of all Phrase attributes, and its functionality, check out the documentation:

Picture entitys

Extensions: images, imageload

Pictures (not to be confused with the HTML5 <picture> element) are the bridge between images and the <canvas> element. Pictures can be created by calling the scrawl.makePicture() factory function. A Picture can also be cloned from another Picture by calling the .clone() function on it. At a minimum, every Picture entity needs to be linked to an Image wrapper object by setting its .source attribute to the Image object's name.

DOM (web page) <img> elements used by Picture entitys can be loaded into the Scrawl library using the scrawl.getImagesByClass(CLASSTAG) and scrawl.getImageById(IDTAG)factory functions, once the web page has fully loaded. This function automatically creates Image objects, using the <img> element's id value as the object's name.

Note that, at this time, the HTML5 canvas API does not support using images from <picture> elements, though some browsers may be able to use <img> elements nested within a <picture> element. Scrawl-canvas does include functionality to handle a srcset attribute within an <img> element; this includes updating the image used by a Picture entity when a browser is resized (eg Chrome browsers appear to treat <img> elements with a srcset attribute as if they are <picture> elements, and will reload appropriately sized images when the browser's dimensions or orientation changes).

Pictures - like Blocks - are drawn from their top-left corner, whose coordinates are stored in its .start attribute. The coordinates of the bottom-right corner of the Picture are relative to the top-left corner, with the offsets stored in entity's .width and .height attributes. In line with other entitys, these attribute values can be absolute (Numbers) or relative to the entity's cell (percentage Strings).

Scrawl permits the use of the following alias attributes for setting and getting a Picture's position and dimensions: .pasteX, .pasteY, .pasteWidth and .pasteHeight.

A Picture can be limited to copying just a (rectangular) portion of an image by setting its .copyX, .copyY, .copyWidth and .copyHeight attributes. Again, Number values are absolute, while percentage String values are relative to the source Image's dimensions. When rendering a Picture entity, Scrawl will automatically limit the copy action to within the permitted bounds of the underlying image:

Using the Picture entity 'copy' and 'paste' attributes

Dynamic loading of images

The ability to define and load images at the same time as the entity is created was introduced in Scrawl v1.01. The url of the image to be used by the Picture entity needs to be supplied (as a string) to the scrawl.makePicture() factory function in the argument's .url attribute.

Loading images into the Scrawl library via scrawl.makePicture() is asynchronous - the entity object will not be created, or added to groups, until after the image has been fully loaded across the network.

An additional pseudo-attribute - .callback - was introduced in Scrawl v2.00. The attribute, which only works with the scrawl.makePicture() factory function, takes an anonymous function which will be run once the image has successfully loaded.

Image data

Any Picture object can have an image data table generated on it:

  1. Make sure the Picture has a name attribute.
  2. Call .getImageData() on the Picture - in most cases this step is no longer required since Scrawl v4.0
  3. Access image data values by calling the Picture's .getImageDataValue({x: number, y: number, ?channel: string}) function.
  4. x and y values are absolute (Number) coordinates relative to the <canvas> element's top left hand corner.
  5. Channel strings are: 'red', 'green', 'blue', 'alpha', or 'color' - if this attribute is not supplied, the Picture will use the value stored in its .imageDataChannel attribute.
Determining the canvas color value at the mouse cursor

Using video elements with Picture entitys

HTML5 <video> elements can be imported into the Scrawl library using the scrawl.getVideoById(#id) function. Once imported, an Image entity can use the Video by setting its .source attribute to the Video object's name String:

Using video as a Picture entity source, and as a pattern

Scrawl video utilisation remains an experimental feature at this time, and is likely to develop and change as the code matures. In particular, different browsers handle the HTML5 <video> element in different ways.

Using images from a different server (CORS)

In general, Scrawl expects images used for Picture entitys to respect the 'same domain' JavaScript policy. Attempting to use images from a different domain will lead to security failures which, while not breaking the code, will result in Picture entitys not being displayed, and patterns displaying as black.

Scrawl is configured to accept cross-domain images where developers have enabled CORS headers on the servers supplying the image files, and have set the crossorigin attribute of DOM image elements to 'anonymous' where appropriate. More information on CORS can be found over at the Mozilla Development Network website, and other places.

Not all web browsers recognise CORS. Mileage may vary.

Convert entitys to Picture entitys

Any entity, or group of entitys, can be converted into a Picture entity using the following functions:

  • Entity.convertToPicture() - for single entitys, or Path entitys with associated 'mark' entitys
  • Group.convertToEntity() - for Groups containing entitys
Markers on Path entity, converted to a Picture entity

Picture object documentation

For complete details of all Picture attributes, and its functionality, check out the documentation:

The SpriteAnimation object

Extensions: images, imageload, animation

Sprite sheets are collections of animation frames held on a single image. The sheet is loaded into the web page just like any other image (in <img> tags), and imported into the Scrawl library using scrawl.getImagesByClass() or scrawl.getImageById().

To make use of the sprite sheet, we need to create some SpriteAnimation objects. Each SpriteAnimation object holds details of the animation frames that comprise a single animated sequence - walking left, walking right, running, turning, jumping up, dying, etc. A single sprite sheet may need dozens of separate SpriteAnimation objects to interpret all the possible animation sequences it contains.

Initialising an animation sheet

SpriteAnimation objects can be created using the scrawl.makeSpriteAnimation() factory function.

The SpriteAnimation .frames[] attribute is an array of JavaScript objects which define the location and dimensions (in px) of each frame on the sprite sheet, and also the duration (in milliseconds) for which the frame needs to be displayed before moving on to the next frame:

  • {x: topLeftX value, y: topLeftY value, w: width value, h: height value, d: duration value}

To vary the speed of an animation, set the SpriteAnimation's .speed attribute to an appropriate value. Speed values > 1 are equivalent to fastForward, while values between 0 and 1 are equivalent to slow motion. Setting the speed to 0 will pause the animation.

The SpriteAnimation .loop attribute determines how the animation will play:

  • end - runs sequence once, then stops
  • loop - when sequence completes, it will loop and continue
  • reverse - when sequence completes, it will reverse its running direction and continue
  • pause - pauses the animation on the current frame

The direction of the animation is controlled by the .running attribute:

  • forward - runs from the first frame to the last frame
  • backward - runs from the last frame to the first frame
  • complete - stops the animation and resets the currentFrame attribute

When the .loop attribute is set to 'loop' or 'reverse', the animation will play continuously. Animations set to 'end' will need to be started by setting the .running attribute to 'forward' or 'backward'. Animations can be paused by setting the .loop attribute to 'pause'.

The SpriteAnimation attributes can be retrieved and changed both directly on the SpriteAnimation, and also by using the .get() and .set() functions on any Picture entity associated with the SpriteAnimation.

Linking the Picture and SpriteAnimation objects

To link a Picture entity to a sprite sheet, set the Picture's .source attribute to the sprite sheet's Image wrapper's NAME value, and its .animation attribute to the required SPRITEANIMATIONNAME String value.

Beyond being associated with a sprite sheet, the Picture entity acts like any other entity - it can be moved, resized and cloned in the normal way.

Displaying the animated entity is achieved by calling scrawl.render() (or an equivalent clear/stamp/compile/show sequence) within a user-coded animation loop.

Amimating a Picture entity with a sprite sheet

Sprite sheet taken from www.kwiksher.com/tutorials-kwik/tutorial-sprites/

To get the Picture to change the animation sequence it is displaying, use Picture.set({animation: SPRITEANIMATIONNAME}). If the new animation sequence is located on a different spreadsheet, then the Picture's.source attribute will also need to be updated.

Fine tuning the current SpriteAnimation can be achieved by calling the Picture.set() function. The entity will pass the function's data object onto its current SpriteAnimation object.

Using entity sheets with Picture entitys

When a Picture object is associated with an SpriteAnimation, the .getImage() function will update the entity's .copy attributes with the current frame's data, in addition to returning the appropriate sprite sheet image. This is routinely handled automatically as part of the display cycle.

Support for sprite sheet generators

Scrawl does not (yet) support importing files from sprite sheet generators such as TexturePacker - users will need to write their own JavaScript to read through the files and extract the required data into SpriteAnimation objects. If anyone does write such a function, I'll be more than happy to add it into Scrawl-canvas!

SpriteAnimation object documentation

For complete details of all SpriteAnimation attributes, and its functionality, check out the documentation:

Shape entitys

Extensions: shape, factories

Scrawl Shapes are Scrawl's way of rendering SVGTiny path data. They can be used to create ellipses, rectangles with rounded corners, regular shapes such as triangles and stars, lines and curves, and more complex paths such as country borders.

Kaleidoscope clock

Shape creation

The simplest way to create a shape is to use one of Scrawl's path/shape factory functions, setting the .shape attribute to true (warning: this attribute is false by default).

  • Straight line - use scrawl.makeLine() or scrawl.makeRegularShape()
  • Quadratic curve (with one control point) - use scrawl.makeQuadratic()
  • Bezier curve (with two control points) - use scrawl.makeBezier()
  • Ellipse - use scrawl.makeEllipse()
  • Rectangle with rounded corners - use scrawl.makeRectangle()
  • Other regular shapes (triangles, stars, etc) - use scrawl.makeRegularShape()

Each factory function has its own set of attributes that help define the shape. The function argument object can also include the regular entity positional and styling attributes.

Attributes that are unique to the factory functions (such as .endX, marked as (*) below) are NOT retained by the Shape object. Thus, they cannot be retrieved or amended using .set() or .get(), and they cannot be used when cloning a Shape entity.

  • .startX Number (px) or percentage String - start x coordinate (default: 0)
  • .startY Number (px) or percentage String - start y coordinate (default: 0)
  • (*) .endX Number (px) or percentage String - end x coordinate (default: 0)
  • (*) .endY Number (px) or percentage String - end y coordinate (default: 0)
  • .startX Number (px) or percentage String - start x coordinate (default: 0)
  • .startY Number (px) or percentage String - start y coordinate (default: 0)
  • (*) .endX Number (px) or percentage String - end x coordinate (default: 0)
  • (*) .endY Number (px) or percentage String - end y coordinate (default: 0)
  • (*) .controlX Number (px) or percentage String - control point x coordinate (default: 0)
  • (*) .controlY Number (px) or percentage String - control point y coordinate (default: 0)
  • .startX Number (px) or percentage String - start x coordinate (default: 0)
  • .startY Number (px) or percentage String - start y coordinate (default: 0)
  • (*) .endX Number (px) or percentage String - end x coordinate (default: 0)
  • (*) .endY Number (px) or percentage String - end y coordinate (default: 0)
  • (*) .startControlX Number (px) or percentage String - start control point x coordinate (default: 0)
  • (*) .startControlY Number (px) or percentage String - start control point y coordinate (default: 0)
  • (*) .endControlX Number (px) or percentage String - end control point x coordinate (default: 0)
  • (*) .endControlY Number (px) or percentage String - end control point y coordinate (default: 0)
  • .startX Number (px) or percentage String - start x coordinate (default: 0)
  • .startY Number (px) or percentage String - start y coordinate (default: 0)
  • (*) .radiusX Number (px) or percentage String - horizontal radius value (default: 0)
  • (*) .radiusY Number (px) or percentage String - vertical radius value (default: 0)
  • .startX Number (px) or percentage String - start x coordinate (default: 0)
  • .startY Number (px) or percentage String - start y coordinate (default: 0)
  • .width Number (px) or percentage String - width (default 0)
  • .height Number (px) or percentage String - height (default: 0)
  • (*) .radius Number (px) - radius value for corners (default: 0)

Rectangles made with this factory function (as opposed to Block entitys) can be given rounded corners by setting the appropriate attributes in the construction object. Setting .radius (which at this time only accepts a Number value) will give all corners the same radius value; this can be overridden by setting one or more of the following:

  • .radiusTopLeftX .radiusTopLeftY .radiusTopRightX .radiusTopRightY
  • .radiusBottomRightX .radiusBottomRightY .radiusBottomLeftX .radiusBottomLeftY
  • .radiusTopLeft .radiusTopRight .radiusBottomRight .radiusBottomLeft
  • .radiusTopX .radiusTopY .radiusBottomX, .radiusBottomY
  • .radiusLeftX .radiusLeftY .radiusRightX, .radiusRightY
  • .radiusTop .radiusBottom .radiusRight .radiusLeft
  • .radiusX .radiusY .radius
  • .radius Number (px) - radius value (default: 0)
  • (*) .sides Number - number of sides (default: 0)
  • (*) .angle Number - degree of angle turn at each point (default: 0)
  • .startX Number (px) or percentage String - start x coordinate (default: 0)
  • .startY Number (px) or percentage String - start y coordinate (default: 0)
  • (*) .startControlX Number (px) or percentage String - x coordinate of first control point, for bezier and quadratic-based regular shapes (default: 0)
  • (*) .startControlY Number (px) or percentage String - y coordinate of first control point, for bezier and quadratic-based regular shapes (default: 0)
  • (*) .endControlX Number (px) or percentage String - x coordinate of second control point, for bezier-based regular shapes (default: 0)
  • (*) .endControlY Number (px) or percentage String - y coordinate of second control point, for bezier-based regular shapes (default: 0)
  • (*) .lineType String - type of line to be used for the regular shape - possible values include: l - line; q - quadratic curve; t - reflected quadratic curve; c - bezier curve; s - reflected bezier curve (default: 'l')
The scrawl.makeRegularShape() factory

The .data attribute

The second approach to creating Shape entitys is to use the scrawl.makeShape() factory function. In addition to accepting all the usual entity attributes in the JavaScript object argument, this function requires us to supply a .data attribute describing the shape to be drawn by the entity.

The data attribute is a string of SVGTiny Path element 'd' attribute commands - as described in the SVG Tiny 1.2 specification. Accepted commands include: M, m, Z, z, L, l, H, h, V, v, C, c, S, s, Q, q, T and t. (In line with the SVGTiny spec, Scrawl does not recognise the arc commands A or a).

Shape entitys - World Map

The .data attribute can be updated at any time by using the .set() function. This allows shapes to by created and updated dynamically:

Scrawl animation - building Shape entitys dynamically

Shape object documentation

For complete details of all Shape attributes, and its functionality, check out the documentation:

Path entitys

Extensions: path, factories

Scrawl paths are complex objects comprising the Path object itself, alongside a series of Point and Link objects that are used to define the shape. Paths can be used to draw any SVGTiny path - lines, curves, triangles, ellipses, etc - just like Shape entitys.

However because Paths are made up of Points and Links, they are more versatile than Shape entitys - for instance the constituent Point objects can be grouped and moved independently of the Path object itself. Points can also be fixed in place while the rest of the Path moves.

Path creation

Path entitys can be created with the same factory functions used to create Shape entitys. In this case, the argument's attribute .shape should be set to false, or omitted:

  • Straight line - use scrawl.makeLine() or scrawl.makeRegularShape()
  • Quadratic curve (with one control point) - use scrawl.makeQuadratic()
  • Bezier curve (with two control points) - use scrawl.makeBezier()
  • Ellipse - use scrawl.makeEllipse()
  • Rectangle with rounded corners - use scrawl.makeRectangle()
  • Other regular shapes (triangles, stars, etc) - use scrawl.makeRegularShape()
Styling the Path (or Shape) entity

Be aware that the .makeLine(), .makeQuadratic() and .makeBezier() factory functions all locate the Path's rotation/reflection at the start of the line; the .makeRegularShape(), .makeEllipse() and .makeRectangle() functions locate the rotation/reflection point at the centre of the entity.

Paths can also be created using the scrawl.makePath() factory function. Like its Shape counterpart (scrawl.makeShape()), this factory function requires us to provide a .data attribute string made up of SVGTiny Path element 'd' attribute commands - as described in the SVG Tiny 1.2 specification.

Drag-and-drop Path and Phrase entitys

Path markers

Markers are (reusable) entitys that can be added to a Path - they can be useful for building more complex arrows and data lines. Any entity can be used as a marker:

  • .markStart string - SPRITENAME - entity to be placed at start of Path's path
  • .markMid string - SPRITENAME - entity to be placed at end of each of the Path's sub-paths
  • .markEnd string - SPRITENAME - entity to be placed at end of Path's path
  • .mark string - SPRITENAME - entity to be placed at start and end of the Path path, and at the end of each of Path's sub-path (unless overridden by .markStart, .markMid, .markEnd
Markers on Path entity

Path object documentation

For complete details of all Path attributes, and its functionality, check out the documentation:

Colors in Scrawl.js

Extensions: color

Colors, gradients and patterns are used in several areas by Scrawl:

  • to give cells a background color - Cell.backgroundColor
  • for stroking entity shapes - [entity].strokeStyle
  • for flooding areas enclosed by entitys - [entity].fillStyle
  • for shadow effects - [entity].shadowColor

The simplest way to define a solid color for any of these attributes is to use a CSS color string:

  • Color names - 'Red', 'silver', etc
  • Hexidecimal rgb color values - '#ff0000' (for red), ''#c0c0c0' (for silver), etc.
  • rgb strings - 'rgb(255,0,0)' (for red), 'rgb(192,192,192)' (for silver), etc.
  • rgba strings - 'rgba(255,0,0,1)' (for opaque red), 'rgba(192,192,192,0.5)' (for translucent silver), etc.
  • other color strings, as supported by various browsers.

The Color object

The Color object is most useful for defining and generating random colors within a set of limits, or for 'animating' the color by manipulating the color's various channels (red, green, blue, alpha). Color objects are created using the scrawl.makeColor() factory function.

Color objects - like gradients and patterns - only work with the .fillStyle and .strokeStyle attributes. To set these attributes to the color, pass the Color's .name attribute to them.

Scrawl animation - changing entity style attributes

Color objects are stored in the scrawl.design section of the library (alongside gradient and pattern objects). For complete details of all Color attributes, and its functionality, check out the documentation:


Extensions: core

A gradient can be built in Scrawl by instantiating a Gradient object (for linear gradients) or a RadialGradient object, then using that gradient's name as the value for entity fillStyle and strokeStyle attributes.

Gradients are created by calling the scrawl.makeGradient() factory function.

Radial gradients, which use circles to define their start and end positions, are created using the scrawl.makeRadialGradient() factory function.

Gradient and RadialGradient objects are stored in the scrawl.design section of the library. Once a gradient has been defined, it can be used by any entity's fillStyle or strokeStyle attributes simply by supplying the gradient's name as the String value:

Creating gradients to use with entitys

Positioning gradients

Just like entitys, gradients can be positioned absolutely (using Number values) or relatively (using String percentage values). Both gradients and radial gradients require a start position and an end position, set through the following attributes: .startX, .startY, .endX, .endY

Radial gradients have two additional attributes - the radius values (using Number px values, or percentage Strings relative to the cell/entity width) for the start and end circles: .startRadius, .endRadius.

Spotlight effect using gradient

Gradient scope

Gradients can take one of two reference scopes:

  • Cell scope - where the position coordinates use the containing cell as their frame of reference
  • Entity scope - where the position coordinates use the entity position and dimensions as their frame of reference

A gradient's scope is determined through its .lockTo attribute, which can be set to either 'entity' (or true) for the entity scope, or 'cell' (or false) for the cell scope. By default, gradients and radial gradients use the cell scope.

Gradients assigned to cells and entitys

Color stops

Gradient .color attributes are Arrays made up of simple JavaScript objects representing color stop data. Each color stop object has two attributes - {color:string, stop:number}. Within these objects the .color strings can be any normal HTML/CSS color string, while the .stop value can be any value between 0 and 0.999999 (not 1).

A gradient can be animated by manipulating the order and values of the color stops in the .color array. The simplest way to do this is to increase or decrease the color stops' 'stop' value by a delta value set in the gradient's .roll attribute:

Animating gradients

Documentation for gradients

For complete details of gradient attributes, and their functionalities, check out the documentation:


Extensions: images

A canvas pattern is a (repeating) image which can be used by entitys as a fillStyle or strokeStyle. Just like gradients (and Color objects), patterns are stored in the design section of the library - for this reason, gradients and patterns should always be given distinct names.

A Pattern object requires an image to to display. Similar to Picture entitys, the simplest way to supply a Pattern object with an image is to preload the image in an html <img> tag and then import it into the library using the scrawl.getImagesByClass() library function. This image can then be assigned to the pattern by setting the pattern's .source attribute to the <img> id value.

Alternatively, a Pattern object can be instantiated with a .url attribute - an URL String to an image file's location on the server. The new object will load the image file using an image.load function. This is an asynchronous call, meaning that entitys making use of the pattern may initially display as black. If the entity is part of an animation loop, it will display its pattern once the image has finished loading.

Creating patterns to use with entitys

A pattern can also be created with a <canvas> element as its image source by setting the pattern's .source attribute to the appropriate CELLNAME String.

Using a canvas as the source for a pattern style

Animating patterns

If the source of the pattern is a Cell or Video wrapper, then the pattern can be animated by animating the cell or playing the video:

Animated patterns

Documentation for patterns

For complete details of Pattern object attributes, and its functionalities, check out the documentation:

The display cycle

Extensions: core

The entire purpose of Scrawl is to display stuff in a <canvas> element on a web page. A project involving Scrawl will often use the following structure to achieve this aim:

  1. Load a web page, including the scrawlCore-min.js file and any additional extension files (or use the scrawl.loadExtensions() function)
  2. When the web page has finished loading, run a javascript script or file involving Scrawl instructions
  3. If not done automatically by Scrawl, define stacks and <canvas> elements for the scene(s)
  4. Import images into the scrawl library, if needed
  5. Import elements into a Scrawl stack, if required
  6. Define any additional cells that will be used by the scene
  7. Define the entitys and designs to be used in the scene, assigning them to cells and groups as necessary
  8. Perform a display cycle:
    1. For animations, perform any necessary entity or cell manipulations
    2. Clear any cells that need to be cleared
    3. Perform further entity or cell manipulations, if required
    4. Stamp entitys onto their cells, and/or get cells to compile their displays
    5. Get pads to show the results of their stamp/compile operations
    6. Perform any necessary HTML element manipulations and/or transforms
  9. For animation routines, start an animation object
  10. In the animation function, repeat the display cycle, moving entitys, cells and elements as necessary

In essence, the display cycle involves three actions:

  • The first step is to clear the cells involved in the scene. This removes any previous display and allows (in particular) animations to be redrawn cleanly, thus giving the impression that entitys (and cells) are moving across the canvas/stack. However, a particular scene may require that some cells are NOT cleared between display cycles - for instance those cells that are being used in parallax scrolling animations. It is also a good idea not to clear the display (visible) cell/canvas until the last moment, after the next frame of the animation has been compiled.
  • The second step is to compile the cells. This involves instructing entitys and groups to stamp themselves onto their cells.
  • The third step is to get pads to show the results of their cells' work on the visible canvas. A pad will always have a minimum of two cells: the display cell, and the base cell; additional cells can be added to the pad to perform various tasks associated with building the scene. The 'show' step involves copying any additional cells onto the base cell, and then copying the base cell onto the display cell.
Magnifier over image

Of course, the above model will not be suitable for every project; for instance a particular scene may call for the creation of new entitys and the removal of old entitys in response to user interactions (such as a game progresses). And some scenes may require more complex manipulations during the display cycle while others will only require a simple render once everything has been set up.

For this reason, Scrawl comes with a range of library and object functions for handling the display cycle. These fall into four main groups:

Clear operations

  • scrawl.clear([PADNAMES])
  • Pad.clear()
  • Cell.clear()

Stamp and compile operations

  • scrawl.compile([PADNAMES])
  • Pad.compile()
  • Cell.compile()
  • Group.stamp(methodString, CELLNAME)
  • Group.forceStamp(methodString, CELLNAME)
  • entity.forceStamp(methodString)
  • entity.stamp(methodString)

Show operations

  • scrawl.show([PADNAMES])
  • Pad.show()

Render operations

Render functions combine clear, compile and show functions into a single render function

  • scrawl.render([PADNAMES])
  • Pad.render()

Clearing cells

Extensions: core

  • scrawl.clear([PADNAMES])
  • Pad.clear()
  • Cell.clear()

The clear commands will completely clear the various <canvas> elements in readiness for drawing. If the Cell's .backgroundColor attribute has been set to a color, then that color will be used to flood the cleared area.

Before using the clear commands, you need to make sure that all the Cells affected by the operation have the following attributes correctly set:

  • For the scrawl and Pad functions, the .rendered and .cleared attributes both need to be set to true before the Cell will clear its canvas.
  • If the Cell function is used, the Cell will clear/flood its canvas regardless of the settings of the other display attributes.

The scrawl.clear() function can take an optional array of PADNAME strings, which will limit the clear action to just those pads. If the function is invoked without an argument, then all Pads on the web page will call their Cell's clear functions.

Stamping entitys onto cells

Extensions: core

  • Group.stamp(methodString, CELLNAME)
  • Group.forceStamp(methodString, CELLNAME)
  • entity.forceStamp(methodString)
  • entity.stamp(methodString)

'Stamping' is the act of getting a entity to draw itself onto a cell, and via that cell onto a visible canvas. The entity.stamp() and entity.forceStamp() methods can be used to draw a entity onto a cell; the functions' argument can be used to override the entity's preset drawing method.

The only difference between the Entity.stamp() and Entity.forceStamp() methods is that the former respects the entity's visibility attribute, while the latter ignores it.

Scrawl entitys have a number of different drawing methods, identified by the following method strings:

  • 'draw' - stamps an outline onto the cell using the strokeStyle color
  • 'fill' - stamps a filled version of the entity onto the cell, using the fillStyle color
  • 'drawFill' - draws, then fills, the entity
  • 'fillDraw' - fills, then draws, the entity
  • 'floatOver' - draws, then fills, the entity - requires a shadow offset
  • 'sinkInto' - fills, then draws, the entity - requires a shadow offset
  • 'clear' - clears an area of the cell using the entity's shape as a template
  • 'clearBackground' - floods an area of the cell with the cell's backgroundColor, using the entity's shape as a template
  • 'none' - processes, but does not draw or fill, the entity; this is particularly useful for updating Path entitys which are used to position other entities, but not themselves displayed
  • 'clip' - rather than draw itself onto the canvas, the entity will set the Cell's clip region to its own path shape

The default method is each entity's own method attribute value.

Scrawl entitys: stamping methods - with added roll

The Group.stamp() function is used in a similar fashion to draw all the entitys in the group onto the desired Cell canvas. If a method argument is supplied, all the group entitys will be drawn using that method. If no cell argument is supplied, the Group will stamp the entity on its default cell. The Group.forceStamp() function ignores the value of the Group's .visibility attribute.

Compiling the scene

Extensions: core

  • scrawl.compile([PADNAMES])
  • Pad.compile()
  • Cell.compile()

The compilation process in Scrawl is in fact a cascade which starts by sending an order to a cell requesting that it compiles (draws) itself. The cell, in turn, asks each of the entity groups listed in its .groups array attribute to forward a stamp command to all the group's entitys (as listed in the group's .entitys array).

At each stage of this cascade (cell→group, group→entity), Scrawl sorts the groups and entitys arrays so that the groups/entitys with the lowest .order attribute are drawn on the cell before those with higher value orders.

Only those groups, and entitys, whose .visibility attribute is set to 'true' will be included in the cascade. To exclude an entity (or group) from the cascade either set its .visibility attribute to 'false' before starting the cascade, or remove the entity (or group) from the Group.entitys (Cell.groups) array, or delete the entity using the scrawl.deleteEntitys(SPRITENAMES) library function.

Using the compile commands is very similar to using the clear commands. Before using the compile commands, you need to make sure that all the Cells affected by the operation have the following attributes correctly set:

  • For the scrawl and Pad functions, the .rendered and .compiled attributes both need to be set to true before the Cell will compile its canvas.
  • The Pad function will sort its associated Cells in line with their .compileOrder attribute, then call each Cell in ascending compileOrder order to perform their compile operation.
  • If the Cell function is used, the Cell will compile its canvas regardless of the settings of the other display attributes.

The scrawl.compile() function can take an optional array of PADNAME strings, which will limit the compile action to just those pads. If the function is invoked without an argument, then all Pads on the web page will call their Cell's compile functions.

3D Carousel effect with selectable items (using path)

Showing the scene

Extensions: core

  • scrawl.show([PADNAMES])
  • Pad.show()

Scrawl will show a scene by:

  1. copying associated Cell canvases onto the Pad's base cell canvas
  2. copying the Pad's base cell canvas onto its display cell/visible <canvas> element
Scrawl animation - moving Cells by manipulating their attributes

The show() functions follow the same model as used for compiling Cells. Before using the show commands, you need to make sure that all the Cells affected by the operation have the following attributes correctly set:

  • For the scrawl and Pad functions, the .rendered and .shown attributes both need to be set to true before the Cell will copy its canvas onto the destination canvas.
  • The Pad function will sort its associated Cells in line with their .showOrder attribute, then call each Cell in ascending showOrder order to perform their show operation.

The scrawl.show() function can take an optional array of PADNAME strings, which will limit the show action to just those pads. If the function is invoked without an argument, then all Pads on the web page will undertake a show action.

Cell manipulation during the show action: position, scale, roll and flip, copy area, global attributes

The order in which cells are copied onto the base cell is important. Cells resemble Picture entitys in their show functionality: a Cell can be positioned, scaled, flipped and rolled on its destination canvas just like a Picture entity can on its destination Cell canvas. Similarly the area of the Cell to be displayed on the destination canvas can be restricted, and a Cell's globalCompositeOperation and globalAlpha attributes will affect how it is stamped on the destination canvas.

The attributes used to determine how a Cell will 'stamp' itself onto its destination canvas are the same as for Picute entitys - see the Picture entity page for more details.

Cell absolute and relative positioning

Rendering a scene

Extensions: core

  • scrawl.render([PADNAMES])
  • Pad.render()

Scrawl's render commands are shorthand functions for undertaking a complete display cycle. When using the render commands all cell, group and entity attribute updates need to be completed before making the render call.

The scrawl.render() function can take an optional array of PADNAME strings, which will limit the render action to just those pads. If the function is invoked without an argument, then all Pads on the web page will undertake a render action.

Scrawl.js spirograph-like simulation

Animations using Scrawl-canvas

Extensions: animation

Scrawl comes with an in-built animation loop function that starts when Scrawl initializes itself. To animate a <canvas> element, coders need to instantiate one or more animation objects which include the necessary instructions for animating the scene.

An animation object can be created using the scrawl.makeAnimation() factory function. The factory takes a JavaScript object as its argument with the following attributes:

  • .name - the the animation object's name (optional)
  • .fn - the animation itself, coded up as an anonymous function containing display cycle instructions
  • .delay - a boolean value that, if set to true, will prevent the animation running immediately after creation (default: false)
Scrawl animation - move and resize a Phrase entity

Unless otherwise instructed (by setting .delay to true), the factory function will start playing the animation as soon as it is created. To stop an animation, use the .halt() function. To re-start the animation, or start a delayed animation, call .run(). To delete an animation from the Scrawl ecosystem, use .kill().

Animation objects are stored in, and can be accessed at, scrawl.animation.ANIMATIONNAME. The names of currently running animations are kept in the scrawl.work.animate array.

The animation loop itself is part of the scrawl library. The loop can be exited (stopping all animations) by setting the scrawl.work.doAnimation flag to false. To restart the animation loop after it has been stopped, set .doAnimation to true and call scrawl.animationLoop().

The animation loop can handle more than one animation object at a time, thus allowing Scrawl to control the animations on multiple canvases. Similarly, a single canvas can have more than one animation object affecting its display.

Documentation for the Animation object

For complete details of the Animation object's attributes, and its functionality, check out the documentation:

Moving entitys

Extensions: animation

To move an entity (or Cell) across a <canvas>, change its .start Vector (alias startX and .startY) attribute between display cycles. This is best achieved by using the entity.set() or entity.setDelta() functions.

Scrawl animation - attach an SVG-based Picture entity to the mouse cursor

Image taken from www.clker.com

Scrawl objects also include a delta Vector (alias deltaX, deltaY) which can be used to move an entity (or Cell) across a canvas by a set amount each time the animation function is called. The following functions make use of these attributes:

  • entity.updateStart() - adds the delta Vector to the start Vector.
  • entity.revertStart() - subtracts the delta Vector from the start Vector.
  • entity.reverse(arg) - reverses the signs on the delta Vector attributes.
  • entity.exchange(object, arg) - exchanges the attributes of two entity objects; argument can be any valid, shared attribute.
Scrawl animation - moving Blocks

Animating other entity attributes

Any attribute that has an effect on the appearance of an entity (or Cell) can be animated:

  • The dimensions of Block and Picture entitys can be animated by manipulating the entity's .width and .height attributes.
  • Wheel entity size can be changed via the .radius attribute.
  • Entitys can be rotated by by incrementing their .roll attribute as part of the display cycle.
  • Changing an entity's .scale attribute will shrink or magnify the entire entity - including line widths, text sizes, etc.
  • An entity's color can be animated by setting the .strokeStyle and .fillStyle attributes to new values as part of a display cycle. Note that the entity context attributes (fillStyle, font, globalAlpha, globalCompositeOperation, lineCap, lineJoin, lineWidth, miterLimit, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, strokeStyle, textAlign, textBaseline) must be changed via the .set() function to have a visible effect on the entity.
  • The image displayed in a Picture entity can be 'moved' and resized by changing the Picture entity's .copyX, .copyY, .copyWidth and .copyHeight attributes.
Scrawl animation - create and delete bezier curves to animate them

Manipulating Point objects

In addition to being animated by any of the above methods, Path entitys can also be animated by manipulating the attributes of its constituent Point objects.

Scrawl animation - moving Path entitys and Point objects

Entity pivots

Extensions: core

A pivot is an object which replaces an entity's startXY coordinate with its own coordinate. By supplying a entity with the name of a Point object as its .pivot attribute's value, the coder is telling that entity to use the Point's local Vector attribute values to locate its position on the cell.

In particular, entitys can use the Point objects of an invisible Path entity (whose method attribute has been set to 'none') to determine their positions on the <canvas> - only the invisible Path needs to be animated; Scrawl will look after the position of any entitys associated with the Path's Point objects.

Scrawl animation - attaching entitys to Point pivots

The pivot value can also be the name of another entity. By combining the pivot attribute with handle offsets, a entity can be associated with another entity, and will move to wherever the pivot entity moves. For instance, this is how the label in demo007 associates with the Block entity, moving to wherever the Block moves so it can be stamped directly above it.

When chaining a series of entitys together by pivots, the order in which the entitys are drawn can become an important issue:

Scrawl animation - attaching entitys to entity pivots


Point objects can be made to accept an entity object as a pivot by setting their .fixed attribute to an ENTITYNAME string.

Moving a entity over a quadratic curve

Mouse, pointer and touch

Extensions: core

Scrawl tracks the position of the mouse cursor, and the current location of any touch events, in relation to the position of every visible canvas element on the web page through a set of internal event listeners. Each Pad object holds this data in its .mice attribute - an object containing continuously updated data on each ongoing event.

To retrieve this data, use the Pad.getMouse() function. The function takes a single argument as follows:

  • null/undefined - returns the current mouse position Vector
  • true - returns all the current mouse/touch Vectors as an Object
  • DOM event object - returns the current mouse/touch Vectors affected by the event, as an Array

The object(s) - an enhanced Vector - returned by the getMouse() function has the following attributes:

  • x - current x coordinate of touch or mouse cursor (in px), from the left side of the canvas.
  • y - current y coordinate of touch or mouse cursor (in px), from the top side of the canvas.
  • active - true if mouse is hovering over the canvas, or the touch is within the canvas's bounds; false otherwise.
  • id - the identifier for the recorded event; this also acts as the attribute name within the Pad.mice Object.

Any entity can be made to track the mouse pointer, or finger, as it moves across the canvas element. To 'attach' an entity to the pointer/finger, set the entity's .pivot value to the string literal 'mouse'; additionally the entity's .mouseIndex attribute needs to be set to the appropriate Vector's .id value.

Attaching a Scrawl entity to the mouse cursor

Drag and drop entity objects

Extensions: core, animation

Scrawl uses four functions to coordinate entity drag-and-drop functionality:

  • var here = Pad.getMouse() - get the mouse cursor's current coordinates (as an {x:value, y:value} JavaScript object).
  • Group.getEntityAt(here) - perform a collision detection check between the mouse cursor's current coordinates and the group of entitys; will return the entity object with the highest .order attribute at that location, or false if no entity was detected.
  • Entity.pickupEntity(here) - amends the entity's .handleX, .handleY, .order, .mouseIndex and .pivot attributes (to 'mouse') so that the entity will now move as the cursor/finger moves.
  • Entity.dropEntity(PIVOTSTRING) - resets the entity's .order and .pivot attributes so that the entity no longer moves as the cursor moves; Entity.dropEntity() sets the entity's pivot attribute to null.

The getEntityAt() and pickupEntity() functions expect to receive an object with attributes .x and .y - if .getMouse returns an array of vectors, or the Pad.mice object, then the array/object will need to be iterated through to (potentially) attach entitys to each ongoing mouse/pointer/touch event.

Scrawl does not include functionality to automatically drag/drop entitys; coders will need to write event listeners (eg for mousedown or touchdown events) which invoke the above functions. This is to allow coders the maximum flexibility in determining how users will interact with entitys in a canvas.

Drag-and-drop Picture entitys, ignoring their transparent zones

All scrawl entitys (including invisible entitys), and even Cells, have the capacity to be dragged:

Cloning Scrawl entitys

Animating entitys along a path

Extensions: path, factories, animation

Any entity can be animated along a path once it has been set up to do so:

Give the following entity attributes an appropriate value, either by including them in the factory function object when creating the entity, or by using the .set() function after it has been created:

  • .pathPlace - a value between 0 and 1, with 0 being at the start of the path and 1 being at the end of it.
  • .deltaPathPlace - a (very small) delta value to be added to the .pathPlace attribute during the animation sequence. Alternatively, the .pathPlace attribute can be set directly using the .set() or .setDelta() functions.
  • .pathSpeedConstant - when set to true, the entity will move along the path at a constant speed; when false the entity will slow down as it negotiates corner curves (default: true).
  • .addPathRoll - if true, the entity will rotate to match the path's slope (default: false)

The path itself is provided by a Path entity. If not already defined, create the Path path and then set the .path attribute of the entitys to be animated along it to the Path's name.

To move the entity, either update the entity's .pathPlace attribute during the animation cycle, or (if .deltaPathPlace has been set) use the .updateStart() function:

Moving entitys along the perimeter of a complex Path

If the .addPathRoll attribute has been set on an entity, it will roll to match the slope of the path as the animation proceeds:

Rotating entitys in line with their Path paths

Moving text along a path

Any Phrase object can be associated with a Path path, simply by setting the Phrase's .path attribute to the Path entity's name. For the best results, set the .addPathRoll and .pathSpeedConstant attributes to true.

Text along a path

Additional demos

Moving an entity over a Bezier curve
Moving a entity over a bezier curve
Measuring the length of a Bezier curve
Measuring the length of a Bezier curve

Cell animation

Extensions: core, animation

Because Scrawl Cell objects include attributes that are used to determine how they are copied to a Pad's base cell during the 'show' stage of the display cycle, and the base cell itself contains information on how it is to be copied to the display cell as the final step in the display cycle 'show' stage, it is possible to animate cells across other cells by manipulating these attributes as part of the animation cycle.

The key attributes are the same as those used for the Picture entity:

  • Cell.copy (alias .copyX, .copyY) - a Vector indicating the top left hand coordinates of the section of the cell which is to be copied onto the base (or display) cell.
  • Cell.copyWidth, .copyHeight - the dimensions of the section of the cell which will be copied.
  • Cell.start (alias .startX or .pasteX, .startY or .pasteY) - the top left hand coordinates on the target (base or display) cell where the copied area will be positioned.
  • Cell.pasteWidth, .pasteHeight - the dimensions that the copied area from the source cell will take on the target cell; if these dimensions differ from the .copyHeight and .copyWidth attributes, Scrawl will stretch or shrink the copied area to fit.

These attributes should never be changed directly; rather, update them via the Cell.set() or Cell.setDelta() functions.

Scrawl animation - moving Cell objects by manipulating their attributes

Cells also have delta attributes to help automate some animation. As for Picture entitys, the .delta Vector affects the .start attribute, while the .copyDelta vector is used with the .copy attribute.

Because the start Vector represents the Cell's reflection/rotation point, it is possible to rotate and reflect the Cell's <canvas> when it is copied to another canvas - these actions are controlled by the .roll, .flipReverse and .flipUpend attributes.

Pivots and paths

Cells are able to use an entity or Point object, or even another Cell, as a pivot to determine its start coordinates. This functionality can be seen in action in the magnifier over image demo where the magnifier cell uses the mouse coordinates as its pivot.

Similarly, a cell can be assigned to sit on or move along a path. I have absolutely no idea how useful this functionality may be.

Scrolling cells

Scrolling effects can be created by animating a cell across a background cell. This allows us to perform effects such as parallax scrolling and cell zooming.

Cell scrolling

Scrolling is often used in games to move backgrounds relative to the main entitys, giving the impression of movement across a scene:

Animated cat across an animated 3D background
  1. Animate a cell across another cell by changing copy or paste attributes.
  2. When the edge of the background cell is reached, splice it.
  3. Shift the animated cell back by the spliced amount, and continue the animation.

Scrawl can splice a cell by calling the Cell.spliceCell() function on it. This function copies an edge strip of a cell, shifts the rest of the cell backwards, and pastes the copied strip back to the opposite edge. The function takes an object with the following attributes:

  • .edge - a string literal: 'horizontal','vertical','top','bottom','left', or 'right' (required)
  • .strip - strip width in px (default: 20)

Parallax scrolling

To achieve a parallax scrolling effect, add some additional cells to a pad and then animate them at different speeds:

Parallax scrolling

Zooming cells

A Cell can be zoomed in relation to another cell by setting the maximum and minimum width/height attributes on a cell and then applying the Cell.zoom() function:

Cell zoom

Cell object documentation

For complete details of all Cell attributes, and its functionality, check out the documentation:

Scrawl Groups

Extensions: core

A Group object connects a set of entity objects to a Cell object; it is through this connection that a Cell will call entitys to stamp themselves onto it, as part of the display cycle.

Groups are also used by cells when they build their collision maps, used to determine which areas of the cell (<canvas>) are in-bounds, and which are out-of-bounds, to entitys.

Third, groups are used for collision detection - for instance at-coordinate collisions where the Group object tests its entity set to see if one of them lies over a given coordinate.

And finally, groups not only collect entitys, they can also manipulate those entitys - moving, scaling and rotating them.

Scrawl animation - moving entitys via their group

Group creation

Each time a Cell object is created, a Group object with the same name as that Cell is also created.

New Group objects can also be created at any time by calling the scrawl.makeGroup() factory function.

Unless otherwise instructed, a newly created Group will associate itself with the current pad's base cell. A Group can be associated with a different cell by setting the factory function's .cell attribute to that cell's name.

Existing entitys can be added to the Group at the time of the Group's creation by setting the .entitys attribute to the entity's name, or giving it an array of entityname strings.

Entitys can be assigned to a group at the time of their own creation, by setting the .group attribute in the factory function's argument object to the desired GROUPNAME.

Also an entity, or an array of entitys, can be added to - or removed from - a Group object at any time by calling various functions:

  • scrawl.addEntitysToGroups(groups, entitys)
  • scrawl.removeEntitysFromGroups(groups, entitys)
  • Group.addEntitysToGroup(entitys)
  • Group.removeEntitysFromGroup(entitys)
  • entity.addEntityToCellFields(cells)
  • entity.addEntityToCellFences(cells)
  • entity.removeEntityFromCellFields(cells)
  • entity.removeEntityFromCellFences(cells)

The library function scrawl.deleteEntity(entitys) automatically removes the entity from all the groups it is associated with.

Group object documentation

For complete details of all Group attributes, and its functionality, check out the documentation:

Entity collision zones and collision points

Extensions: core

Each class of Scrawl entity has its own means of determining when something has collided with it. Every entity has its own collision zone, which can be tailored to the needs of different entity classes. Collisions are reported by interrogating the entity with a set of collision coordinates (objects with x and y attributes) - if a coordinate lies within the entity's collision zone, it will report a hit.

Complementing the collision zone, each entity also comes with a set of collision points. These generate the collision coordinates which can be used to check for collisions with other entitys or the Cell's collision field.

Details of the entity's collision points, and instructions on how the entity should implement its collision zone, are held by the entity object itself in a set of attributes (which vary between entity classes).

Block and Phrase entitys

Blocks, as the simplest Scrawl entity, have the simplest collision detection system. The Block collision zone covers the width and height of the Block.

Scrawl automatically takes entity handle offsets, rotation, flip orientation, and scaling into account when determining entity hits:

Scrawl collisions - Block entity collision zones

The Block/Phrase collision points can be placed at the corners of the block, and midway along each side; an additional collision point can be added at the centre. Each collision point can be switched on by including it in the .collisionPoints attribute array; groups of collision points can be activated by using the shorthand strings 'all', 'perimeter', 'edges', 'corners', 'center', and/or 'start'.

Scrawl collisions - Block.collisionPoints =

Picture entitys

With no instructions otherwise, a Picture entity will act like a Block entity, setting its collision zone to match its width and height, and generating collision points in the same manner as Blocks.

For Picture entitys which have up-to-date image data, as generated by calling the Picture.getImageData() function on the entity, a second type of collision zone can be generated, which takes into account the image data at the collision point. In this scenario, various attributes need to be set:

  • Picture.imageDataChannel - channel to be used for collision detection (string, options: 'red', 'green', 'blue', 'alpha'; default: 'alpha')
  • Picture.checkHitUsingImageData - on true, use image data to calculate collisions; on false, use Block method for detecting collisions (boolean, default: false)
Scrawl collisions - Picture entity collision zones

Shape entitys

Shape entitys generate their collision points in the same manner as Block entitys. Be aware that, depending on the shape of the path displayed by the Shape, some of these collision points may be some distance from the visible part of the Shape.

Shape collision detection zones are the areas within the Shape's path.

Wheel entitys

Wheel entitys differ from Block entitys in that they use their radius value (rather than width and height) for calculating collisions. They also adjust their corner collision points so that they sit on the wheel's circumference:

Scrawl collisions - Wheel.collisionPoints =

Wheel entitys can also take a number as their collisionPoint value, to generate that number of collision coordinates around the entity's circumference.

Wheels have an additional attribute - Wheel.checkHitUsingRadius. If this boolean attribute is set to false, Wheel objects will calculate collisions using the JavaScript function .isPointInPath() - this allows incomplete wheels to accurately return collisions:

Scrawl collisions - Wheel entity collision zones

Path entitys

Path entitys use different methods for calculating their collision points. The .collisionPoints attribute can takes an integer number which represents the number of collision points on the Path's path, spaced equidistantly between the path's start and end points. They can also use floating point values between 0 and 1 to position a collision Vector at that distance along their path.

Like Shape entitys, the Path entity collision zone is the area within the Path's path.

Scrawl collisions - Path entity collision zones

Most browsers will assume, when checking for collisions with lines and curves, that the Path's start and end points have been closed:

Scrawl collisions - Path entity collision zones - lines and curves

At-coordinate collision detection

Extensions: core

All collision detection in Scrawl relies on feeding a coordinate, or an array of coordinates to a collision function. The coordinate system used is cartesian in nature, local to the Cell object (which wraps a <canvas> element), with coordinates (0,0) being in the top-left hand corner of the canvas. Measurements are in pixels.

The simplest way to check whether a entity is present at a given coordinate is to call the Group.getEntityAt(coordinate) function. Used in conjunction with the Pad.getMouse() function, which returns a Vector of the mouse cursor's current position over the <canvas> element, Scrawl can implement an effective drag-and-drop mechanism for moving entitys around the canvas.

The Group.getAllEntitysAt(coordinate) works just like .getEntityAt, but this time the function will return an array of all entitys colliding with the supplied coordinate.

A third approach is to use the Group.getEntitysCollidingWith(entity) function, where all the entitys in the group are checked to see if they are colliding with a reference entity supplied as the function's argument:

Scrawl.js image tile puzzle

Groups can be used to speed up collision detection. The Group.regionRadius attribute can be used to quickly winnow out entitys that are beyond the radius value, thus allowing Scrawl to concentrate its efforts on checking only the more likely collision coordinates for a hit with one of that group's entitys.

Cell collision field

Extensions: collisions

A collision field is a simple map (actually, an image data object) created by Cell objects from the entitys assigned to their CELLNAME_field and CELLNAME_fence Groups. These groups are generated automatically whenever a Pad object (for a visible <canvas> element) is created.

Scrawl Cells build their collision fields dynamically whenever the scrawl.buildFields() library function is invoked. In essence, the Cell builds its collision field by creating a black background and then stamping any entity included in its _field Group (in white) onto that background. It then stamps the entitys included in its _fence Group (in black) onto the background, and captures the resulting image as an image data object. A link to the image data object is stored in the Cell.fieldLabel attribute.

Entitys can be included in a Cell's _fence or _field Group when they are created, by setting an entity.field or .fence attribute in the factory's argument object to 'true'.

Alternatively, a entity can be added to a Cell's _field or _fence Group by calling the entity.addEntityToCellFields() or entity.addEntityToCellFences() functions. They can be removed by calling the entity.removeEntityFromCellFields() or entity.removeEntityFromCellFences() functions.

Detecting collisions with the Cell collision field

To check for collisions, call the Group.checkField() or Entity.checkField() functions. The parameters for the checks are held by the Group/entity objects in their .fieldChannel and .fieldTest attributes.

Scrawl collisions - build a Cell collision field using entitys

Using color in a Cell collision field

Cells are not restricted to black-and-white collision fields. Any image data object can be used as a collision field - all that needs to be done is to assign that image data object's NAME value to the Cell.fieldLabel attribute.

If a color collision field is being used, then entitys need to be set up to take advantage of it. This is done by assigning appropriate values to the entity.fieldChannel and entity.fieldTest attributes. Legal values for these attributes are:

  • .fieldChannel - 'red', 'green', 'blue', 'alpha', 'anycolor' (default: anycolor)
  • .fieldTest - integer between 0-255 (for alpha channel, float between 0-1), which represents the minimum threshhold for the channel color that needs to be surpassed before the test returns 'true' (default: 0)

When a cell detects a collision, it will return an Array composed of [SPRITENAME, VECTOR] data, where the Vector represents the collision coordinates.

Using colors in a Cell collision field

Group collisions

Extensions: collisions

Compared to Cell field collision testing, Group collision testing is fairly simple. Scrawl Groups have two functions, for testing entitys within the Group for any collisions taking place between them, and for testing one group of entitys against another group of entitys for possible collisions:

  • Group.getInGroupEntityHits()
  • Group.getBetweenGroupEntityHits(arg) - where the argument can either be a GROUPNAME string, or the actual Group object against which to test for collisions

In each case, the result will be an array containing a set of [ENTITYNAME, ENTITYNAME] arrays detailing those entitys currently in-collision at the time of testing.

In-group collision examples

Scrawl collisions - in-Group collision detection (Wheel, Path)
Scrawl collisions - in-Group collision detection (Picture)

Between-group collision examples

Scrawl collisions - between-Group collision detection (Block, Phrase)
Scrawl collisions - between-Group collision detection (Wheel, Path)

Scrawl filters

Extensions: filters

Scrawl includes some basic filters which can be applied to individual entitys, groups, cells, and pads.

Scrawl image filter

Adding a scrawl filter to an entity or group is a two-step process:

  1. Create the filter
  2. Add the FILTERNAME String to an entity's (or group's) .filters array

The application of the filter to the entity can be delayed. By default, the filter is applied as soon as the entity stamps itself onto the cell during the cell compile process. However, if the entity's .filterLevel attribute is changed to 'cell' or 'pad' then the application is delayed as follows:

  • entity.filterlevel = 'cell' - filter is applied once the cell's 'compile' step is complete
  • entity.filterlevel = 'pad' - filter is applied as the last step in the pad's 'show' step

For more details on Scrawl's display cycle - see the Displaying scenes section of this tutorial.

Applying filters at the entity, cell and pad levels

Creating filters

A filter can be created by calling the appropriate filter factory function. The factory function takes a single argument of a JavaScript object, which consists of key:value attributes. All filter factory arguments can take the following attributes:

  • .name - the filter name
  • .alpha - the filter strength - when a filter is applied to an entity, it will normally replace the source pixels with the filter result pixels (alpha = 1); when the filter's alpha attribute is set to less than one, a percentage of the original entity's pixels will be combined with the filter
  • .composite - the global composite operation to be used when combining the original entity pixels with the filter's result pixels - if more than one filter is applied to an entity, then the last filter's composite value is used. See Demo 78 for a list of permitted composite values.


The blur filter uses the concept of a brush for calculating the blurring effect. The brush is an oval shape which can be sized and rolled to create speed-blur effects.

Calculating the effect of a large blur brush can take a considerable amount of time. This time can be cut by only performing the calculations on a subset of the brush's pixels. Calculation times can also be shortened by excluding all transparent pixels in the filter's target from the calculation.

Scrawl image filters - blur

Factory function: scrawl.makeBlurFilter()

Argument attributes:

  • .radiusX - horizontal radius (in px) of the blur brush - default: 2
  • .radiusY - vertical radius (in px) of the blur brush - default: 2
  • .roll - roll, or angle (in degrees) of the blur brush - default: 0
  • .skip - an integer number representing which pixels in the brush to calculate; a value of 2 will calculate every other pixel, 3 will calculate every third pixel, etc - default: 1
  • .includeInvisiblePoints - whether invisible pixels in the target entity or cell should be included in the calculation - default: false


Adds a brightness filter effect to an entity

Scrawl image filters - brightness

Factory function: scrawl.makeBrightnessFilter()

Argument attributes

  • .brightness - Percentage value of brightness effect: as a Number, between 0 (black) and 1 (default - no effect); as a String, between '0%' and '100%'. Values can go above 1 or 100%


Adds a channels filter effect to an entity - manipulate the intensity of each color channel

Scrawl image filters - channels

Factory function: scrawl.makeChannelsFilter()

Argument attributes

  • .red - value of red channel, from 0 or 0% upwards beyond 1 or 100% - default: 1
  • .green - value of green channel, from 0 or 0% upwards beyond 1 or 100% - default: 1
  • .blue - value of blue channel, from 0 or 0% upwards beyond 1 or 100% - default: 1


Adds a channel step filter effect to an entity - manipulate the color space in each color channel

Scrawl image filters - channelStep

Factory function: scrawl.makeChannelStepFilter()

Argument attributes

  • .red - step value of red channel, between 1 (256 steps, default) and 128 (2 steps)
  • .green - step value of green channel, between 1 (256 steps, default) and 128 (2 steps)
  • .blue - step value of blue channel, between 1 (256 steps, default) and 128 (2 steps)


Adds a greyscale filter effect to an entity. The Scrawl greyscale filter is optimised to produce decent greyscale versions for a range of images, but in certain circumstances a better greyscale may be achieved by using a tint filter instead

Scrawl image filters - greyscale

Factory function: scrawl.makeGreyscaleFilter()

(No additional argument attributes)


Adds an invert filter effect to an entity - colors are swapped for their opposite value on the colorwheel

Scrawl image filters - invert

Factory function: scrawl.makeInvertFilter()

(No additional argument attributes)


'Leaching' is a form of chroma key or 'green screen' process where certain color ranges are removed (made transparent) in an entity or cell. The scrawl leach filter allows several color ranges to be defined for removal.

Unlike other filters, the leach filter uses an 'xor' global composite operation to stamp itself onto the canvas - this is changeable, if necessary.

The exclude array should contain a set of arrays defining the color ranges to be leached from the image. Each array within the exclude array must include the following six numbers in exactly this order: [minRed, minGreen, minBlue, maxRed, maxGreen, maxBlue], where the numbers are integers between 0 and 255

Scrawl image filters - leach

Factory function: scrawl.makeLeachFilter()

Argument attributes

  • .operation - any valid global composite operation string (default: 'xor')
  • .exclude - an array of color range arrays (default: [])


The scrawl matrix filter is a form of convolution matrix image processing, which can be used for a range of effects including blurring, sharpening and edge detection.

The matrix itself does not need to be of equal dimensions (its width and height values can be different). Larger matrices take longer to process. The matrix weightings data is supplied as a one-dimensional array of numbers.

Scrawl image filters - matrix

Factory function: scrawl.makeMatrixFilter()

Argument attributes

  • .width - the width of the matrix, in pixels (default: 1)
  • .height - the height of the matrix, in pixels (default: 1)
  • .x - the 'home' cell in the horizontal plane (default: Math.floor(width/2))
  • .y - the 'home' cell in the vertical plane (default: Math.floor(height/2))
  • .includeInvisiblePoints - whether invisible pixels in the target entity or cell should be included in the calculation (default: false)
  • .data - array of Number values representing the weights to be applied to each cell in the matrix, where the first number is the weight for the top left cell, the next number is the weight for the cell to the right of the first cell, etc.


Adds a noise filter effect to an entity, where 'noise' is the result of swapping pixels. The noise filter uses a brush (see the blur filter, above) to limit the area in which pixels will be swapped, with a larger brush generating more noise. The strength attribute determines the likelihood of pixel pairs being swapped.

Scrawl image filters - noise

Factory function: scrawl.makeNoiseFilter()

Argument attributes

  • .radiusX - horizontal radius (in px) of the noise brush - default: 2
  • .radiusY - vertical radius (in px) of the noise brush - default: 2
  • .roll - roll, or angle (in degrees) of the noise brush - default: 0
  • .strength - the intensity of the noise effect, ranging from 0 (no noise) to 1 (maximum noise) - default: 0.3


Adds a pixelate filter effect to an entity. The width and height of the pixel blocks can be set, as can the offset positions.

Scrawl image filters - pixelate

Factory function: scrawl.makePixelateFilter()

Argument attributes

  • .width - pixel block width, in px (default: 5)
  • .height - pixel block height, in px (default: 5)
  • .offsetX - horizontal coordinate from which to begin pexelization (default: 0)
  • .offsetY - vertical coordinate from which to begin pexelization (default: 0)


Adds a saturation filter effect to an entity

Scrawl image filters - saturation

Factory function: scrawl.makeSaturationFilter()

Argument attributes

  • .saturation - Percentage value of saturation effect: as a Number, between 0 (grey) and 1 (default - no effect); as a String, between '0%' and '100%'. Values can go above 1 or 100%


Separate colours to show primary or secondary colour channels only

Scrawl image filters - separate

Factory function: scrawl.makeSeparateFilter()

Argument attributes

  • .channel - string containing one of the following values: 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'all' (default)


A quick method for creating a tint filter that outputs a sepia effect

Scrawl image filters - sepia

Factory function: scrawl.makeSepiaFilter()

(No additional argument attributes)


A quick method for creating a matrix filter that outputs a sharpen effect

Scrawl image filters - sharpen

Factory function: scrawl.makeSharpenFilter()

(No additional argument attributes)


Adds a threshold filter effect to an entity. Effectively, this filter first converts an entity to a greyscale, and then a black/white image where white is assigned to pixels above a given threshold level and black to the remaining pixels.

Scrawl image filters - threshold

Factory function: scrawl.makeThresholdFilter()

Argument attributes

  • .threshold - percentage value of threshold effect: as a Number, between 0 (all black) and 1 (all white); as a String, between '0%' and '100%' (default: 0.5)


The scrawl tint filter offers a means to assert fine control over an entity's color palette, where the color of a pixel is based on enhancing or supressing the combined contribution of each input channel to each output channel - play with the demo to see what tinting effects can be achieved.

Scrawl image filters - tint

Factory function: scrawl.makeTintFilter()

Argument attributes

  • .redInRed - value between 0 and 1 - default: 1
  • .redInGreen - value between 0 and 1 - default: 0
  • .redInBlue - value between 0 and 1 - default: 0
  • .greenInRed - value between 0 and 1 - default: 0
  • .greenInGreen - value between 0 and 1 - default: 1
  • .greenInBlue - value between 0 and 1 - default: 0
  • .blueInRed - value between 0 and 1 - default: 0
  • .blueInGreen - value between 0 and 1 - default: 0
  • .blueInBlue - value between 0 and 1 - default: 1

Additional examples

Applying filters to videos

Using video as a Picture entity source, and as a pattern

Applying filters to groups

Grouped filter effect; filtering on wheel perimeter

Filters documentation

For complete details of Scrawl's filter capabilities, check out the documentation:

The Scrawl Vector and Quaternion objects

Extensions: core

The Scrawl library uses Vector objects extensively in its code base. Fortunately, users have to know nothing whatsoever about them to use the library.

Similarly, Scrawl stacks use Quaternion objects for calculating rotations in 3D space, but users are spared this particular horror because the orientation of DOM elements can be set using good old-fashioned Euler rotations (pitch, yaw, roll).

Vector and Quaternion object documentation

For complete details of all Vector and Quaternion attributes, and their functionalities, check out the documentation:

Saving and loading Scrawl objects

Extensions: saveload

The save-load extension is an experimental feature which is likely to change significantly as development proceeds.

Scrawl includes support for saving and loading object data as JSON strings. This support is dependent on the scene structure (<canvas> and stack elements, Pads, Cells, <img> elements, etc) already being in place when a save or load operation is performed.

To save a Scrawl object, use the .toString() function. This will return a JSON string or - in the case of entitys, groups, cells and pads - an array of JSON strings representing the object and other objects (such as gradients) associated with it.

More general save operations can be carried out using the scrawl.save() function - though the results of this operation may include duplicate objects.

Save Scrawl entitys using .toString()

To load a previously saved JSON String, or array of JSON Strings, use scrawl.load():

Scrawl load - entire pad
Scrawl load - patterns

Save and load documentation

For further details of Scrawl's save and load functionality, check out the documentation:

The Scrawl physics engine

Extensions: physics

The physics engine extension is an experimental feature which is likely to change significantly as development proceeds.

The Scrawl physics engine is largely based on the book "Physics for Game Developers" by David M Bourg and Bryan Bywalec (O'Reilly Media). Any mistakes in the code base are my fault, not theirs.

At the current time (version 5.0.3) the physics engine only supports particle physics, not rigid body physics, modelling.

Assumptions made in the physics engine

While the engine doesn't assume much, the following assumptions are fundamental to its operation:

  • The coordinate system matches the system used throughout Scrawl, with an origin at the top left corner.
  • The x axis points to the right; the y axis points down. Negative values are up and to the left of the origin.
  • The z axis points out of the screen towards the user.
  • One pixel defaults to a measurement of 1 meter. Mass is measured in kilograms, time in seconds, speed in meters per second, etc. Full details of particle default units can be found in the particle documentation.

The physics engine is entirely virtual. Defining a set of particles, springs and forces and then animating them will display nothing on the <canvas>. Scrawl does allow particle objects to be treated in a similar way to regular entitys; this includes allowing an entity to use a particle object as its pivot.

To help construct a physics model, the scrawl library includes a physics object (scrawl.physics) where model-wide variables can be stored. Two variables - scrawl.physics.gravity and scrawl.physics.airDensity - are defined when Scrawl initializes; additional variables can be added in the normal JavaScript manner, for example: scrawl.physics.windSpeed = 15;

The scrawl.physics object also includes a .deltaTime attribute which, for each iteration of the model, should be set to the time elapsed (in seconds) since the previous iteration ran.

Scrawl treats Particle objects as if they are entitys - for instance all particles can be accessed at scrawl.entity.PARTICLENAME; for this reason, Particle objects should always be given unique names. Updating Particle positions and velocities occurs whenever Scrawl undertakes the compile component of the display cycle. The position of an individual Particle can also be calculated by calling the Particle's .stamp() function.

Particle objects

Particles are small objects that have attributes such as mass, surface area, drag (relating to the roughness of their surface area) and elasticity, determining how they react in a collision with other particles and surfaces. They also include position and velocity data, stored in Vector objects.

To create a new Particle, use the scrawl factory function scrawl.makeParticle(). An existing particle can be cloned using the .clone() function. Both functions can take an object argument to set the .mass, .radius or .surfaceArea, .drag, and .elasticity attributes - see the particle documentation for default values for these attributes.

Particle position and initial velocity data can be set using the pseudo-attributes .startX, .startY, .deltaX and .deltaY.

Particle attributes can be changed at any time using the .set() and .setDelta() functions. Be aware that (re)setting a Particle's attributes while a model is running may well ruin it.

Force objects

Particle movement is achieved by applying forces to a particle. These forces are used to recalculate the Particle's .velocity vector before adding it to the .position vector.

The physics engine expects forces to be presented to it as JavaScript functions which accept a single argument - the Particle object to which the force is to be applied. The product of the force function should be a force vector, which the function should vectorAdd to the Particle's .load vector.

Force functions are added to a particle using the Particle.addForce() function. The addForce function can accept an anonymous function as its argument, or alternatively a FORCENAME string of a force object stored in the scrawl library.

Scrawl currently ships with two predefined force objects: scrawl.force.gravity (to apply gravity to a Particle); and scrawl.force.drag, which adds air drag to the Particle.

Additional forces can be added to the scrawl library by creating Force objects using the scrawl.makeForce() factory function. This function takes an object with two attributes as its argument: .name, and .fn.

See the documentation for more details about Force object attributes and functionality.

Particle collisions

The physics engine currently supports linear collision calculations. If two particles are colliding, the collision force can be applied to them both using the Particle1.linearCollide(Particle2) function, where Particle1 and Particle2 are the objects in collision.

The physics engine does not include any collision detection functionality. Instead, use regular entity collision detection to determine if two entitys (using Particles as their pivots) are colliding.

Particle collisions within a Cell's collision field can also be detected using the regular entity collision functionality. To get an accurate bounce from an immovable object, define a Particle with a very large mass and, when a field collision is detected, move that Particle to the collision point and linear collide it with the Particle whose entity failed the test.

Spring objects

Springs can be used to connect two Particles together, with a given distance between them. They can be created using the scrawl.makeSpring() factory function. Alternatively, add a new Spring to a Particle using the Particle.addSpring() function.

Unlike Particles, Spring objects are not updated as part of the regular display cycle, as Scrawl does not treat them as entitys. Instead they have their own section in the scrawl library; every Spring will be saved at scrawl.spring.SPRINGNAME. To update Spring attribute values as part of each iteration of the physics model, call scrawl.updateSprings() library function.

See the documentation for more details about Spring object attributes and functionality.

Getting physics-based models to work

As far as I can work out from the book, physics models are delicate things which need to be tweaked in various ways to work effectively. This seems to involve playing with a fair number of Particle, Force and Spring attributes until the model runs in a manner that (you hope) looks believable, if not accurate. There may be sacrificial chickens involved in this activity, but I haven't yet coded up any rigid body functionality into the physics engine, so I can't confirm this rumour at the present time.

One of the main factors for formulating chaos seems to be JavaScript floating point calculation rounding errors. One method of defeating inaccuracy is to use more sophisticated methods for calculating force loads on a particle. The physics engine supports three such calculation methods: Euler (the default method), Improved Euler, and RungeKutter (the most accurate and time-intensive method). To change a Particle's calculation method, set its .engine attribute to either 'euler', 'improvedEuler', or 'rungeKutter'.

Please remember that the Scrawl physics engine is experimental. Use with caution!

Physics engine documentation

For further details of Scrawl's physics engine functionality, check out the documentation:

Faster and more efficient animations in Scrawl

Creating animated scenes that involve hundreds of entitys can have an impact on rendering speed and animation frame rates. For instance, every time Scrawl creates a new entity, it also creates a context object for that entity. And every entity takes up memory - the more memory taken up storing data on entitys, the less memory is available to do interesting stuff with those entitys:

There are a number of ways of making a scene render more efficiently. Some of these refer to canvas animations in general, while others are specific to Scrawl.

Tips for faster animations

  • Smaller canvases are faster canvases - if your web page contains several small animations scattered across the page, use a separate, small canvas for each animation.
  • Only animate that which needs to be animated - separate animated and static content into different, overlaying canvases (or, with Scrawl, Cells in a Pad) and only update the canvas (Cell) containing the animation.
  • Minimize calls to the canvas element's context engine - if you have a set of red entitys, and a set of blue entitys, try to arrange things so that all red entitys are drawn together, then all blue entitys are drawn together.
  • Avoid shadows - shadows are an animation killer; only use them if you really need them.
  • Avoid filters except where absolutely necessary.
  • Precalculate as much as possible - try to limit the amount of code in the animation loop, for instance by defining and creating all entitys before the animation starts.
  • Use other technologies where it makes sense to use them - html5 canvas elements are not in competition with animated svg elements, or with CSS3 3d animation functionality; if svg does the job better, use it. The best results may well come from mixing technologies, using the strengths of one to overcome the weaknesses in another.
  • Be creative with interactivity - in particular, poorly planned and executed event handlers can block animation functionality.
  • Think outside the box - can you build the scene in a more effective way? Can you reuse entitys, rather than creating new ones? Can the scene be made more efficient by breaking it down into smaller components?

Scrawl entitys, and groups, include some flag attributes which can be set to help an animation become less memory-hungry and a bit faster:

The single most effective method of speeding things up, in Scrawl, is to reuse entitys wherever possible. For instance, there is no particular reason why entity positioning data needs to be held in the entity object; using an array to hold that information is just as efffective, and a lot faster:

Also, it may make sense at times to use the Canvas API drawing functionality directly, instead of over-relying on Scrawl to do the work. Direct API drawing calls will always be quicker, and can be made on any scrawl cell via the cell's 2d context engine which can be found at scrawl.context.CELLNAME

Using tweens to animate Scrawl objects

Extensions: animations

A Scrawl tween defines a change of state - usually positional, though many things can be tweened - for an set of objects over a given duration. Tween objects are stored in the tween section of the Scrawl library. They can be created using the scrawl.makeTween() factory function, and a tween can be cloned from another tween using the .clone() function.

Internally, a tween object relies on a Ticker object to control its timing functionality. For simpler tweens however, we do not need to worry about tickers.

Create and run Tickers and Tweens

A standalone Tween object can be initialised by setting the following attributes:

  • A .duration value - either a Number (as milliseconds) or a String value: '5000ms' and '5s' are both 5 seconds
  • The .targets attribute can accept either an ENTITYNAME String or the entity object itself; it can also accept a mixed array of Strings and objects.
  • The .cycles Number is a positive integer that sets the number of times the tween will cycle once it is started. Defaults to 1 representing a single cycle; a value of 0 will make the tween cycle indefinitely.
  • Setting the .reversed flag will make the tween run backwards; the .reverseOnCycleEnd flag makes the tween run alternately forwards and backwards for multiple cycles.
  • The .definitions array takes raw JavaScript objects which define the changes to be made to the targets over the course of the tween.

Tween definitions objects

A tween can operate on more than one target attribute at a time. For each attribute that is to be tweened, a definitions object - a plain old JavaScript object - needs to be added to the tween's .definitions array.

A definitions object includes the following attributes:

  • .attribute - a String containing the attribute to be tweened (default: '')
  • .start - a Number or String containing the start value for the attribute (default: 0)
  • .end - a Number or String containing the end value for the attribute (default: 0)
  • .integer - a Boolean flag - when set to true the tween will round intermediate floating point values to the closest integer value (default: false)
  • .engine - the String name of the easing engine to be used when tweening this attribute (default: 'linear'). Scrawl includes a set of 15 built-in engines covering the most common easing requirements.
Tween built-in easing engines

Running and controlling a tween

Unlike an Animation object, a tween will not run until it is told to. The following functions can be used on a tween to control its animation:

  • .run() - start a tween running from its start (or end) values
  • .halt() - halt a running tween
  • .resume() - start a tween from the point at which it was previously halted
  • .seekTo(value) - move a tween's internal tick value to the supplied value (in milliseconds)
  • .seekFor(value) - alter a tween's internal tick value by the supplied value (in milliseconds, can be negative)
  • .kill() - delete the tween from the Scrawl library

As for any Scrawl object, a tween's attributes can be altered at any time using the .set() function. Note that setting the .definitions and .targets Arrays will replace those attributes with newly supplied values. To add a new target to the existing targets array use the .addToTargets() function; similarly a target can be removed from the tween using the removeFromTargets() function.

Ticker controls

Advanced tween features

Firstly, tweens can take an additional attribute - .action - that holds a function which can be called each time the tween completes a tick. The function should accept no arguments. Tween attributes (such as the .targets Array) can be referenced using this within the function. Note that when cloning a tween with an .action function, the new tween will reference the original tween's function unless the clone's argument includes a fresh .action function

Next, tweens are not restricted to the set of 15 in-built easing engines. The .engine attribute of a definitions object will also accept a function. This function must take three arguments, in the following order:

  • .start - which is the effective Number value of the definition's start attribute
  • .change - which is the effective Number difference between the definition's start and end attributes
  • .position - which is a Number value between 0 and 1 representing the ratio (milliseconds since tween started / tween duration in milliseconds)

The easing engine function must return a single value which the tween can then use to set the associated attribute in its target objects. The value does not need to be a number - for instance in Learning Task 13 we use an easing engine which outputs a Shape entity .data attribute, which the tween then uses to change the shape of its target Shape. (LT13 also includes an example of using the tween .action attribute, described above).

Finally, the tween's .targets Array is not limited to holding entity objects. Any object which has a Scrawl .set() function can be tweened - including gradients and color objects:

Gradient and color tween animation

Tween documentation

For further details of tween functionality, check out the documentation:

Scrawl tickers and actions

Extensions: animations

Scrawl tweening animations are built on three components: Ticker objects, Tween objects and Action objects. Together, these objects can be used to build animation timelines for use in a canvas scene.

Tweens are described in a separate section of this tutorial. This section describes Tickers and Actions.

Ticker objects

A scrawl ticker represents a controllable time duration. Tweens and actions subscribe to a ticker through their .ticker attribute (which is the String TICKERNAME of the ticker). Their .time attribute - a Number or time-related String value, or alternatively a percentage string value relative to the ticker's duration - determines when the tween will start or the action will trigger.

Tickers can be created using the scrawl.makeTicker() factory function. Tickers can also be cloned from another ticker using the .clone() function. Tickers are animation objects and are stored in the animation section of the Scrawl library.

Tickers take the following attributes:

  • A .duration value - either a Number (as milliseconds) or a String value: '5000ms' and '5s' are both 5 seconds. If the duration is not defined, then the ticker will automatically calculate its duration from the time and duration values of its subscribed tweens and actions.
  • The .order Number determines the order in which an active ticker will run, relative to other active tickers and animation objects.
  • The .cycles Number is a positive integer that sets the number of times the ticker will cycle once it is started. Defaults to 1 representing a single cycle; a value of 0 will make the ticker cycle indefinitely.
  • The .eventChoke attribute sets the interval (in milliseconds) between ticker events being emitted; a value of 0 (the default) surpresses event emmission.
  • If the .killOnComplete Boolean is set to true (default: false) then the ticker will self-destruct once it completes all its cycles.
  • .subscribers - an Array containing TWEENNAME and ACTIONNAME Strings which use this ticker to control their start times.

Rather than use the .set() function to update the .subscribers array, use the ticker .subscribe() and .unsubscribe() functions.

Sequence multiple tweens on a ticker

Ticker objects share the same control functions as tweens, alongside some additional functions:

  • .run() - start a ticker running from its start (or end) values
  • .halt() - halt a running ticker
  • .seekTo(value) - move a ticker's internal tick value to the supplied value (in milliseconds)
  • .seekFor(value) - alter a ticker's internal tick value by the supplied value (in milliseconds, can be negative)
  • .resume() - start a ticker from the point at which it was previously halted
  • .reverse() - reverse the ticker's direction of travel
  • .reset() - set ticker to initial values
  • .complete() - set ticker to final values
  • .kill() - delete the ticker from the Scrawl library.
  • .killTweens(value) - delete the subscribed tweens and actions from the Scrawl library; if the value argument is set to true then will also delete itself.

There is no need to update tweens and actions separately. Note that the seekTo() and seekFor() functions will cascade down to all the ticker's subscribers.

Building and running a timeline with Ticker and Tween objects

Ticker event

Tickers can be made to emit a JavaScript CustomEvent at given minimum intervals (as mediated by the RequestAnimationFrame animation loop). While this event's "bubbles" and "cancelable" attributes are set to true, be aware that the event has only been tested against the window object, not any element within the DOM. Event listeners that are listening on the windows object should pick up these ticker events.

The CustomEvent name is tickerupdate, and contains a detail object with the following attributes:

  • name - String: the ticker's name attribute
  • type - String: always 'Ticker'
  • tick- Number: effective milliseconds since the ticker started its current cycle
  • reverseTick - Number: effective milliseconds remaining before ticker completes its current cycle

Action objects

A Scrawl Action object wraps a set of functions that will be triggered at a given time along a ticker's duration. Like tweens, actions are stored in the tween section of the Scrawl library.

Actions can be created using the scrawl.makeAction() factory function. Cloning actions is not recommended unless fresh functions are supplied in the clone argument's object.

An action object includes the following attributes:

  • .ticker - String TICKERNAME of the ticker to whict this action subscribes
  • .time - Number or String representing the time at which the action's functions will trigger
  • .targets - Array of targets to which the action will apply its function's manipulations
  • .reversed - Boolean - when true, uses the ticker's reversTick value rather than its tick value to determine whether to trigger its functions
  • .reverseOnCycleEnd - Boolean - when true, will automatically reverse the action's direction at the end of each ticker cycle
  • .action - the Function to run when the Action object is triggered by its ticker (when moving forwards along the ticker)
  • .revert - the Function to run when the Action object is triggered by its ticker (when moving backwards along the ticker)

The action and revert functions often mirror each other - for instance making the entity targets visible when moving forward and invisible when moving backward. Mirrored functions allow the ticker to run its timeline animation in response to system or user input beyond absolute time progression - for instance a user dragging a range input forwards or backwards, or a video playing or rewinding.

The action object's functions should not accept any arguments. They can access their parent action's attributes using this, and can batch set all targets using the this.updateTargets(items) function.

Actions and tickers

Actions have a much more limited set of functions conmpared to tweens and, unlike tweens, an action's ticker cannot be controlled by invoking .run(), .halt(), etc functions on the action. The list of action functions includes:

  • .addToTicker(String) - subscribe to ticker - will unsubscribe from other tickers first
  • .removeFromTicker(String) - unsubscribe from ticker
  • .addToTargets(items) - add objects to targets array; argument can be an OBJECTNAME String, or the object itself, or a mixed Array of such Strings and Objects
  • .removeFromTargets(items) - remove objects from targets array; argument can be an OBJECTNAME String, or the object itself, or a mixed Array of such Strings and Objects
  • .kill() - delete action object from Scrawl library
Ticker event

Ticker and Action documentation

For further details of Ticker and Action object functionality, check out the documentation:

Scrawl stacks

Extensions: stacks

There are a number of very good JavaScript canvas libraries to be found on GitHub and similar venues. Some of these libraries do an excellent job of simplifying and extending the native canvas element API.

When I first started developing Scrawl, I had a vision for the HTML5 <canvas> element that went beyond the functionality of those libraries. I wanted the <canvas> element to be an integral, first-class member of the HTML family – not an add-on (like Flash), but rather something that can be added to any website ... and add value to that website.

I wanted a system where boxes and circles on the canvas can interact on an equal footing with all the other DOM elements on the webpage. Where canvas entitys and DOM elements shared a common language for positioning, sizing and styling; for animations and tweens.

Animated cat across an animated 3D background

Scrawl attempts to achieve this vision through the concept of Scrawl stacks. In a stack, DOM elements (including the <canvas> element) can be treated like any other Scrawl entity. Elements can be positioned, flipped, rotated and animated in the stack exactly like Block entitys can be positioned and animated on a canvas. This includes letting DOM elements use entities as pivots or paths (and vice versa).

Additionally, Scrawl prepares the stack element so that CSS3 3d transforms can be applied to its child HTML5 elements. Scrawl also prepares those child elements to keep track of their transform coordinates, and supplies a number of functions to instigate and animate those transforms. (For more information on CSS3 3d transforms, check out David DeSandro's Intro to CSS 3D Transforms articles.)

Be aware that CSS3 3d transforms are an emerging and unsettled technology. Browser support for the technology varies, and different browsers interpret the standards in different ways. When using Scrawl stacks, always test the browser for CSS3 3d support and prepare ways for the web page to degrade gracefully to show simpler canvas scenes, or images.

Creating scrawl stacks

The (second) obligatory 'Hello, World!' example

<!DOCTYPE html>

    <title>Hello, World</title>

    <div id="myStack" class="scrawlstack withcanvas">
      <p id="myElement">Hello, World!</p>
    <script src="path/to/scrawlCore-min.js"></script>
      var mycode = function() {
        'use strict';

        //update stack div dimensions and styling
          width: 400,
          height: 300,
          border: '1px solid red'

        //move canvas element behind stack div (and p element)
          translateZ: -1

        //update p element dimensions and styling
          startX: 'center',
          startY: 'center',
          handleX: 'center',
          handleY: 'center',
          font: '24px Arial, sans-serif',
          width: 180,
          height: 40,
          color: 'red',
          backgroundColor: 'lightgrey',
          textAlign: 'center',
          paddingTop: '5px'

        //create entity
          pivot: 'myElement',
          fillStyle: 'lightgrey',
          radius: 60

        //update the stack and canvas display

      //load extensions; initialize and run code
        path: 'path/to/minified/extensions/folder/',
        extensions: ['stacks', 'wheel'],
        callback: function() {
          window.addEventListener('load', function() {

            //initialize scrawl object

            //run canvas code
          }, false);

Just as Scrawl can auto-detect existing canvas elements in a web page when the scrawl.init() function runs, so can it detect stacks. To Scrawl, a stack (not to be confused with the HTML/CSS DOM definition of a stacking context) is any DOM element which includes the class scrawlstack.

Any element identified by Scrawl as a stack will be wrapped in a Stack object which is then stored in the Scrawl library in the location scrawl.stack.STACKNAME. The wrapper supplies a range of functions for manipulating the stack's environment, turning the stack element (generally a DOM <div> element) into an analogue of a scrawl Cell.

Additionally, Scrawl will import any direct children of the stack into the library, wrapping them in Element objects and storing them in the library at the location scrawl.element.ELEMENTNAME. Scrawl element objects are analogous to entity objects: they can be positioned and manipulated just like Block entitys.

Because of the need to store stacks and elements in the scrawl library, it is important to give the DOM elements unique id values, or name values. If that information is not supplied in the DOM, then Scrawl will auto-generate names for each wrapper and set the (unpredictable) name as the DOM element's id.

All elements within a stack are absolutely positioned, and are initialized with start coordinates of (0, 0) - which is at the top left hand corner of the stack. The positions of each element will need to be set within the JavaScript code, followed by a call to (typically) scrawl.render() to make sure elements are positioned correctly in the stack when it first displays to the user.

Both stack and element objects come with .get() and .set() functions. The set() function can accept (most) CSS3 attributes - see the above code for example. Hyphenated CSS3 attributes (for example, 'padding-top') need to be converted to camelCase attributes in the set() function's argument object ('paddingTop'), and most CSS attribute values need to be passed as Strings. Particular exceptions to this rule are dimension (width, height) and position (startX, startY, handleX, handleY) attributes, which expect to receive number or percentage string values. The .delta, .translate and (for stacks only) .perspective attributes also expect their values to be numbers.

Attaching an SVG element to the mouse cursor in a Scrawl stack

If the stack's DOM element also includes the class withcanvas, Scrawl will auto-generate a canvas element, and associated wrappers and controllers, and add it to the end of the stack element's child nodes. The canvas element will have an id of 'STACKNAME_canvas', and its Pad controller will be stored in the library at scrawl.pad.STACKNAME_canvas

Be aware that by default the new canvas element will lie over other child elements, thus interfering with native mouse/touch interactivity. This can be fixed by setting the canvas's Pad controller's .translateZ attribute value to less than the stack's .translateZ value (typically -1).

Programmatically creating Scrawl stacks; adding elements to stacks dynamically

A scrawl stack can be added to the web page dynamically in two ways:

  • scrawl.addStackToPage()
  • scrawl.addCanvasToPage()

For both methods, the argument object needs to include a .stackName attribute - a string value which will act as both the stack object wrapper's name and the new DOM <div> element's id.

To place the new stack in the page, the argument's .parentElement attribute needs to be set to the id of the stack's parent element. Alternatively, the element itself can be the value of this attribute.

The .width and .height attributes will set the initial width and height of the stack. Where a canvas is also being added to the page, its dimensions will match its parent stack's dimensions.

Programmatically creating a stack and canvas elements

Stack wrapper objects include two functions for importing elements into the stack:

  • stack.addElementById()
  • stack.addElementsByClassName()

In both cases, the argument is a string identifying the element(s) to be imported, either by id or by classname. The functions work by moving (not cloning) the identified elements into the stack, appending them to the end of the children list. On being moved, all elements are given absolute positioning and assigned a start coordinate of (0,0); their placement within the stack will need to be set in the JavaScript after the DOM manipulation completes.

Adding HTML elements to a Scrawl stack

Positioning elements and pads in a stack

Positioning of elements in a stack follows the same pattern as for the positioning Block entitys on a scrawl cell. The start vector (set using the .startX and .startY attributes) mark the element's rotation/reflection point. The handle attribute (.handleX and .handleY) offset the element from the start coordinates. Values for these attributes can be either relative (percentage strings) or absolute (numbers, with (0, 0) representing the top-left corner of the stack (for start) or element (for handles)).

The .width and .height attributes can also be relative - percentage strings representing a percentage of the stack's dimensions - or absolute (numbers measuring pixels). By default all elements in a stack have 'border-box' box sizing, thus padding and border values are included in the width/height calculation.

For relative dimensions, elements will take into account both the stack's actual dimensions and its .scale attribute value when calculating their own dimensions.

Elements are also able to set their height attribute to 'auto'. As only the immediate children of a stack are counted as scrawl elements, and the scrawl element can contain any number of (normal) DOM elements, the 'auto' value will take the cumulative heights of these DOM elements into consideration when calculating the element's height. Setting an element's height to 0 or '0%' has the same effect as setting it to 'auto'.

Setting element width and height as a percentage of the stack's dimensions

When a stack element's position is determined relatively by setting its .pivot attribute to the ELEMENTNAME of another element (or pad), it can be locked to the edge of that element by setting its .lockTo attribute to one of the following strings: 'top', 'bottom', 'left' or 'right'. If left unset, the normal pivot rules apply.

For details on how to set a group of elements to share equal height or width values, see the Element groups section of this tutorial.

Locking elements horizontally and vertically

Finally, elements, pads and stacks within a stack may be positioned relative to the browser's viewport by setting their .viewport attribute to true. All number and percentage string positions and dimensions will use the viewport's top left corner, and the viewport's dimensions, to size and position themselves.

Positioning and sizing relative to the browser viewport

3d effects

Scrawl stacks are initialised to allow the elements they contain to be positioned in three dimensions on the screen. To this end, every scrawl stack has a perspective attribute. A perspective requires a 'vanishing point' coordinate, and a 'depth' value - by default a stack will set the vanishing point coordinate at the center of the DOM <div> element, with a depth of 0 (no 3d depth). These values can be changed via the .perspectiveX and .perspectiveY (position), and .perspectiveZ (depth) attributes.

Scrawl entitys and cells have a .roll attribute, which sets their rotation (in degrees) in the Z axis. Scrawl elements extend the rotation concept to the X and Y axes through their .pitch and .yaw attributes respectively. These attribute names come from aircraft terminology - for more information see the Wikipedia article.

To animate a 3d rotation, new angle values can be calculated and the element updated via its set() function. Alternatively, delta changes can be stored in the element's .deltaPitch, .deltaYaw and .deltaRoll attributes. These values will be added to their counterparts whenever the scrawl.update() function is invoked.

CSS3 animation in a Scrawl stack div using two canvas elements

To position a stack element in 3d space, set their .translateX, .translateY and .translateZ attributes to appropriate values. Unlike handles, these values map directly to their CSS3 3d counterparts.

Internally Scrawl stacks use quaternions to calculate 3d rotation and positioning of stack elements. This avoids 'gimbol lock' (which I used to think was a disease of the goat). Both the .rotation and .deltaRotation attributes are stored as quaternions, meaning that they can be manipulated using other quaternion objects.

CSS 3d rotating cube in Scrawl stack

Stacks, mouse pointers and touch events

Scrawl stacks are analogous to Scrawl pads, in that they provide a frame within which elements can be positioned and animated. Just like pads, stacks will keep track of the mouse pointer position when it moves over them. All the mouse/touch related functions that apply to pads (such as .getMouse()) will also work with stacks.

Be aware that tracking mouse or touch events across a stack or pad that has been rotated in any way will result in some surprising outcomes, dependent on browser.

Test mouse tracking on rotating canvas element

Scaling stacks

Unlike normal DOM elements, Scrawl stacks can be scaled by setting their .scale attribute to an appropriate level. Elements and pads whose dimensions have been set relative to the stack size - using percentage strings - will resize in line with their stack's scale.

Note that a stack's, or element's, scale does not extend to the scale of any text in those elements. Text scaling needs to be performend separately; an element's text size can be set using the CSS fontSize attribute via the .set() function - percentage values seem to work well for this functionality.

Resizable CSS 3d rotating cube in responsive Scrawl stack

Stack elements and tweens

Stack elements can be used in Scrawl tweens and timelines just like Scrawl entitys:

Animated caption over image
Easing DOM elements - Scrawl tweens

Integrating stack elements and scrawl entitys

As mentioned above, stack elements (and pads) can be treated in much the same way as Scrawl entitys. Elements can use entitys, points (and particles) as pivot objects, and are happy to be animated along Path entitys. Similarly, entitys can use elements as their pivot objects.

Position DOM elements using pivot

Updates to element position, dimension and other attributes don't take effect until an .update() function runs on the stack. The display cycle render functions will update entitys and elements at the same time.

Easing DOM elements - scrawl Paths

Stacks documentation

For further details about the Stacks extension, check out the documentation:

The ElementGroup object

Extensions: stacks

ElementGoups link stacks and elements in the same way that normal Groups link cells and entitys. Every element in a stack, or added to a stack, is also added to that stack's ElementGroup.

The stack's group will share the same name as its stack, and is stored in the library in the group section at scrawl.group.STACKNAME.

ElementGroups act in a similar manner as normal Group objects, and can include entitys as well as elements. Entitys can be manipulated through ElementGroups just as they are with regular groups:

Drag and drop entitys and elements via an ElementGroup

The ElementGroup object includes a number of additional attributes and functions for manipulating groups of elements. For instance, it is possible to make a group of elements share equal heights and/or equal widths by setting their ElementGroup's .equalHeight or .equalWidth attributes to true.

Element positioning within a stack, including scaling; locking canvases to stacks

ElementGroup functions include:

  • elementGroup.addElementsToGroup()
  • elementGroup.removeElementsFromGroup()
  • elementGroup.addEntitysToGroup()
  • elementGroup.removeEntitysFromGroup()
  • elementGroup.updateElementsBy() - add values to element attributes
  • elementGroup.updateEntitysBy() - add values to entity attributes
  • elementGroup.updateBy() - add values to element and entity attributes
  • elementGroup.setElementsTo() - replace element attributes with new values
  • elementGroup.setEntitysTo() - replace entity attributes with new values
  • elementGroup.setTo() - replace element and entity attributes with new values
  • elementGroup.pivotElementsTo() - pivot elements to a given element, entity, point (or particle) so that they can be moved as a group

ElementGroup documentation

For further details about the Stacks extension, which includes ElementGroup objects, check out the documentation:

The Frame entity

Extensions: frame, (stacks)

The Frame entity, first included in version 5.0.0, introduces the concept of indirect perspective to the 2-dimensional canvas element. It is, essentially, an adaption of the Picture entity, with the following key differences:

  • The Frame entity is positioned in a cell not by a single start vector, but rather through four positioning vectors - one for each corner of the entity
  • Each corner can be positioned anywhere on the cell, without reference to the position of the other corners (they are not required to form a rectangular shape)
  • Each corner can be positioned using absolute Number or relative percentage String (or string literal) values; they can also be positioned by reference to another object acting as a pivot or path for the corner
  • Because of this corner independence, Frame entitys do not have a use for entity rotational concepts such as flipReverse, flipUpend or roll - these effects are instead achieved by judicious positioning of each corner
  • Becausae there is no single rotation/reflection (start) vector, Frame entitys do not have any use for a handle vector for offsetting the entity from the start point
  • Frame entitys have no need of dimensional data (width, height), nor can they be scaled - again, this functionality is achieved by placing corners at the appropriate positions to achieve the desired effect
  • Frame entitys do, however, make use of the Picture copy concept
  • A perspective effect can be achieved by positioning the entity's corners in a manner so that the entity looks like it has been placed at an angle to the rest of the scene
  • Unlike Picture entitys, which use mediator objects (Image, Video, Cell) and have to set their source attribute to an IMAGENAME, VIDEONAME or CELLNAME String value, Frame entitys directly access their source objects - a Frame will set its source attribute to an ASSETNAME (for image and video) or CANVASNAME (for canvas cell) String value
Perspective transform a Frame entity by manipulating its corners

Frames can be created by calling the scrawl.makeFrame() factory function. A Frame can also be cloned from another Frame by calling the .clone() function on it.

To directly feed coordinate data to the corners, use the .cornersData attribute. This is an array containing eight items of data: x and y coordinates for each of the four corners. The default data order for the cornersData array is stored in the .cornersDataArrayOrder attribute, which comprises 8 strings as follows:

  • default order - ['tlx', 'tly', 'trx', 'try', 'brx', 'bry', 'blx', 'bly'], where
  • t - top
  • b - bottom
  • l - left
  • r - right
  • x - x coordinate
  • y - y coordinate

To change the order in which the coordinate data is presented to the Frame entity - for instance to match data order from 3rd party tracking software - just change the order of the strings in the .cornersDataArrayOrder Array.

Cloning a Frame entity

To position a Frame's corners by reference - using pivot or path - when initialising or cloning it, or to subsequently update a Frame's position via the .set() or .setDelta() functions, use the following attributes in the function's argument object:

  • .topLeftPath, .topRightPath, .bottomRightPath, .bottomLeftPath
  • .topLeftPathPlace, .topRightPathPlace, .bottomRightPathPlace, .bottomLeftPathPlace
  • .topLeftDeltaPathPlace, .topRightDeltaPathPlace, .bottomRightDeltaPathPlace, .bottomLeftDeltaPathPlace
  • .topLeftPathSpeedConstant, .topRightPathSpeedConstant, .bottomRightPathSpeedConstant, .bottomLeftPathSpeedConstant
  • .topLeftPivot, .topRightPivot, .bottomRightPivot, .bottomLeftPivot
  • .topLeftLockX, .topRightLockX, .bottomRightLockX, .bottomLeftLockX
  • .topLeftLockY, .topRightLockY, .bottomRightLockY, .bottomLeftLockY
Attach a Frame entity's corners to a Path entity

One of the side effects arising from the method used by Scrawl to reshape the Frame's contents is the appearance of a moire-type interference pattern across the frame. Scrawl neutralises this artefact by repeatedly resizing the image before passing it on to its final destination cell. This resizing is controlled by two attributes: .interferenceLoops (number of times the image is resized, default: 2) and .interferenceFactor (the resizing ratio, default: 1.03). Should an interference pattern appear in the final result, try using different values for these attributes.

Decorating a stack element with a Frame entity

A second use of the Frame entity is to decorate a stack element. The Frame can be associated to any stack element by setting its .lockFrameTo attribute to the required ELEMENTNAME String. If the element does not already exist, then a DOM <div> element will be created and added to the stack.

When a Frame is locked to a stack element, it uses that element to determine the coordinates of its corners. The element can be positioned as normal, and rotated using the normal Euler attributes (pitch, yaw, roll). The element's positioning and rotational attributes can also be updated via the Frame - eg frame.set().

Note that for this to work, the stack will need to be associated with its own canvas - this is achieved in the normal way by initialising the stack with the classes "scrawlstack withcanvas".

Lock a Frame entity to a CSS3 3d transformed element

Frame documentation

For further details about the Frame extension check out the documentation:

Responsive <canvas> elements

tl;dr - If you want responsive canvases to be a part of your RWD website, use scrawl-canvas.

The Responsive Web Design (RWD) Wikipedia article defines RWD as: ... an approach to web design aimed at crafting sites to provide an optimal viewing and interaction experience - easy reading and navigation with a minimum of resizing, panning, and scrolling - across a wide range of devices [...] A site designed with RWD adapts the layout to the viewing environment by using fluid, proportion-based grids, flexible images, and CSS3 media queries.

The key phrase for this discussion is "flexible images". Translated, this means that:

  1. images should display cleanly, within the bounds set for them, and scale to fit into the browser (or grid) view appropriately; and
  2. image filesize should be appropriate for the device consuming them - smaller files should be served to handheld devices, compared to the image files required to display on large screens.

HTML5 introduced the new <picture> element to meet the requirements of RWD flexible images. However this new element doesn't (yet) solve the problem for images used as part of a <canvas> element's display; by definition, canvas elements can only source their image inputs from <img>, <video> and other <canvas> elements.

A further problem is that CSS treats <canvas> elements in much the same way as it treats <img> elements - setting the width and height of a canvas via CSS can distort the canvas's output. Canvas dimensions are set directly as attributes on the element (measured in px), and are not the same as CSS block dimensions which, for the purposes of RWD, should ideally be set in proportional units.

Finally, programming the interactions with a <canvas> element - by mouse or by touch - can be difficult at the best of times. But when trying to do this with a "flexible canvas" the task of converting mouse/touch coordinates (measured in px) into the correct position on a canvas can quickly turn into a nightmare.

Implementing a responsive canvas in a web page

If we want to implement a responsive canvas in a page layout we will have to tackle all the above issues, which we can break down as follows:

  1. Make the <canvas> element "flexible"
  2. Keep the <canvas> dimensions in proportion to prevent display distortions
  3. Use "flexible images" to reduce page weight and download times
  4. Accurately position graphics and text on the canvas, whatever its current dimensions
  5. Interact with the canvas, using both mouse and touch, accounting for its current dimensions

Make the <canvas> element "flexible"

There's no getting away from the fact that if we want to resize the canvas, then we have to do it programmatically. Setting the canvas width and height values via CSS will change its visible size, but not its drawing dimensions. The output will rarely be crisp, especially if a canvas with small drawing dimensions is forced to cover a much larger visual area.

Instead, we have to use JavaScript to set the canvas drawing dimensions to match the visual display. One simple approach is to put the canvas inside a container which can be resized using CSS. Then each time a resize action takes place (for instance a mobile view changes from portrait to landscape) a JavaScript resize event listener - appropriately debounced - can interrogate the container to extract its new computed dimensions and apply those values to the <canvas> element's width and height (not style.width or style.height) attributes.

This approach has the added benefit of being able to integrate the canvas with CSS media queries. However care should be taken when applying padding, border and margin values to the container: ideally these should all be set to zero, to minimize confusion when extracting its current dimensions. Such styling could instead be applied to an outer container.

One thing we must remember is that each time we change a canvas's width or height, the browser will automatically clear the canvas display. For animated canvases (using a Request Animation Frame loop) this will not be an issue as the canvas will be redrawn up to 60 times each second. For static displays, though, we will need to redraw the canvas ourselves. If the canvas drawing routines are kept in a JavaScript function, we can make our work a lot simpler.

Keep the <canvas> dimensions in proportion

Scaling a canvas in line with its container is all well and good, but what happens if the container width doubles while its height trebles? Most likely we will end up with a poorly positioned, or distorted, canvas scene. This could occur if the canvas is part of a fluid grid system where each cell in a row has equal height.

Solving this problem is a 2-step process. First, instead of getting the height value directly from the container (in the JavaScript resize event listener), we calculate it as a proportion of the width value. Designing the canvas scene so that its ratio of height to width never changes will keep the calculations simple.

Second, we can use CSS to position the container within the grid or page. For instance, the CSS object-fit property could do the job (with an appropriate polyfill for IE, of course).

Use "flexible images" to reduce download times

If we are going to use images in our canvas, then we need to use them "flexibly". But as we saw above, we cannot (yet) make use of the inherently flexible <picture> element as our image source.

Fortunately most modern browsers now allow <img> elements to use the picture element's srcset and sizes attributes. This allows us to specify a range of images which the browser can choose from, and outline parameters to help the browser choose the most appropriate image for its current display. Finally the src attribute can be used to specify the default image for browsers that do not support the new attributes.

The 2d Canvas API is, for once, kind to us when dealing with flexible images. The API doesn't care about choosing an appropriate file to download. It cares only that the <img> element downloads a file, and uses that data as its image source.

There is one gotcha to watch out for with this approach. Certain browsers (Chrome, I'm looking at you!) have taken the functionality further: if the environment in which the image displays changes significantly, then the browser will dynamically download and display a more appropriate image file. This can have unexpected consequences for an unwary canvas implementation.

Accurately position graphics and text on the canvas

On the face of it, maintaining an accurate representation of a canvas display would seem to be one of the most difficult issues to solve. Canvas composition relies on lines, shapes, texts and images being absolutely positioned using pixel coordinates - and pixel coordinates, by definition, don't scale.

In fact the solution is simple: use a second canvas. We can create a canvas element dynamically with JavaScript and add it to a document fragment which, unlike the DOM, is never displayed in the browser. By setting the dimensions of this hidden canvas to static values which match the proportions of the visible <canvas> element in the DOM, and making sure the invisible canvas is larger than the visible <canvas> is likely to be on desktop monitors, we can give ourselves a stable environment for composing our canvas output.

Canvas drawing now become another 2-step operation. First, draw everything onto the hidden canvas. Then, when this has completed, copy the invisible canvas display over to the visible <canvas>. Job done!

Interact with the canvas, using both mouse and touch

RWD assumes nothing about the device on which a web page will be displayed, thus it is up to us to add functionality for handling user interaction with the <canvas> element from both mouse and touch events. In an ideal world every browser would understand and use pointer events. We do not live in an ideal world; it is our job to make sure our responsive canvas can handle input from a variety of sources.

Just as important - possibly more important: don't forget accessibility issues. Can a user interact with your canvas using the keyboard? Have you included descriptions alongside the canvas scene to explain its purpose and usability to those not using visual browser technology? Web designers and developers have a legal duty to make their sites accessible!

Whichever method we use to gather information on the coordinates of a user click or touch, this information will only relate to the visible <canvas> element. If (as recommended) we are using a hidden fragment canvas for most of our scene composition and interaction then those coordinates will need to be converted. For x coordinates, divide the value by the visible canvas width and multiply it by the hidden canvas width; use height values to get the y coordinate.

One last issue: scaling a canvas is not enough when it comes to RWD interactivity. We also need to make sure that the interactive hit zones on the canvas remain large enough for people to see, and use, on small mobile screens. This means we will have to add some checking functionality to our JavaScript canvas drawing functions which will size and position buttons and labels (small text is not legible text on a canvas) appropriately for the visible <canvas> element's current dimensions.

Using Scrawl-canvas to generate responsive canvases

The tour page on this site meets the requirements for RWD: it uses a fluid grid for positioning components, and media queries to change the layout according to the environment in which the page displays. All images used on the site use srcset and sizes attributes in the <img> elements.

The main part of the page comprises twelve responsive canvases which all use the Scrawl-canvas JavaScript library to handle most of the issues raised above. In particular:

  • The tour page uses scrawl stacks to act as the canvas containers.
  • A JavaScript resize event listener updates the stack <div> dimensions - resizing the visible <canvas> is handled automatically by scrawl.
  • Scrawl treats each visible <canvas> as a Pad object, which creates a hidden canvas attached to a DOM fragment.
  • These base cell canvases are given static dimensions - for the tour page, we use 800px width and 400px height as we designed the tour page fluid grid columns to never exceed a width of 800px.
  • When resizing occurs scrawl automatically handles any outfall from a browser downloading a more appropriately sized image file.
  • We define and position scrawl entitys using relative (%-based) coordinates, which means we don't have to worry about pixel calculations.
  • The scrawl display cycle handles updating the hidden canvas and copying the hidden canvas over to the visible canvas.
  • We use scrawl event listeners to monitor mouse, touch and pointer interactions with the canvas for each canvas; these event listeners automatically handle coordinate calculations for us.
  • We check the browser environment using the scrawl.device object, which allows us to tailor each canvas scene to match the browser's, and device's, capabilities.
  • We use the scrawl animation functionality to drive canvas animations and interactions; to minimise the tour page's impact on the browser only one canvas is animated at any one time.
  • Many of the animation routines use scrawl tweens and timelines, which have no problem using relative (%-based) positions for their calculations.

Event listeners

Extensions: core

Native event listeners

Scrawl comes with two convenience functions for binding and removing event listeners to DOM <canvas> (and any other) element:

  • scrawl.addNativeListener(event, function, target)
  • scrawl.removeNativeListener(event, function, target)

These functions are convenience functions - they do not replace JavaScript's normal processes for adding or removing event listeners to elements. For both functions:

  • the event argument is the normal JavaScript name of the event (eg: 'click') - this argument can also be an array of event names
  • the function argument is either an anonymous function to be performed when the event(s) occur, or alternatively a variable containing the function
  • the target argument is either a css query string which can be used to get the elements that the event listener(s) are to be attached to or removed from, or alternatively the actual element itself; this argument can also accept an array of elements

Mouse, pointer and touch events

Scrawl includes five custom events for tracking interactions with DOM <canvas> elements. These events combine the classic mouse events with Microsoft-inspired pointer events and mobile/tablet touch events. These events are: down, up, enter, move and leave.

These event listeners must be added to or removed from canvases using the following functions. The function arguments are the same as for the convenience functions above:

  • scrawl.addListener(event, function, target)
  • scrawl.removeListener(event, function, target)

Be aware that the custom events were added to Scrawl in version 4.2 and, as such, may still contain bugs that lead to unexpected outcomes in various browsers and devices.


Extensions: core, stack, images

The scrawl.device object holds details about the browser window - dimensions and current view of the page (scrolling):

  • scrawl.device.width
  • scrawl.device.height
  • scrawl.device.offsetX
  • scrawl.device.offsetY
  • scrawl.device.isLandscale() - true if width > height
  • scrawl.device.isPortrait() - true if height > width

It also holds a set of boolean environment attributes detailing the browser's functionality. These tests are run as part of the scrawl.init() function. Note that some of these tests are asynchronous (they don't resolve immediately) and one - .videoForceFullScreen - will only resolve after the first user interaction with the web page:

  • scrawl.device.canvas - does the browser support the <canvas> element
  • scrawl.device.canvasEvenOddWinding - does the <canvas> element support the path-based even-odd winding rule
  • scrawl.device.canvasDashedLine - does the <canvas> element support dashed-line stroke functionality
  • scrawl.device.canvasGcoSourceIn - does the <canvas> element properly support the 'source-in' global composite operation
  • scrawl.device.canvasGcoSourceOut - does the <canvas> element properly support the 'source-out' global composite operation
  • scrawl.device.canvasGcoDestinationAtop - does the <canvas> element properly support the 'destination-atop' global composite operation
  • scrawl.device.canvasGcoDestinationIn - does the <canvas> element properly support the 'destination-in' global composite operation
  • scrawl.device.canvasGcoCopy - does the <canvas> element properly support the 'copy' global composite operation
  • scrawl.device.video - does the browser support the <video> element
  • scrawl.device.videoAutoplay - does the browser permit video to autoplay
  • scrawl.device.videoForceFullScreen - does the device force web page based videos to play in full-screen mode
  • scrawl.device.videoAsCanvasSource - can the <canvas> element use a <video> element as an image source
  • scrawl.device.transform - does the browser support CSS3 3d transforms

Device documentation

For further details about the device object, check out the documentation: