The code for this post is available here.

Assumed knowledge: some prior experience with the terminal and ssh keys. This project builds upon a previous code design boilerplate code project.

Now that the design is clear, the remaining part is the canvas. With a canvas, we can render the graphics, and we can listen for the input events. The result will be a kind of API, and a single class will interact with this API to then provide the final “prototyping” space. This contents of this class will look similar to p5, with some setup code, a draw method, handlers for the input events, and mouse position helpers.

Set up

  • Firstly, clone the repository, and checkout the canvas branch.

    • git clone git@github.com:drohen/js-canvas-boilerplate.git

    • cd js-canvas-boilerplate

  • Ensure dependencies are installed, run: npm i

  • Ensure the code runs in development mode: npm start

Typings

There are two new observable interfaces added to this project, defined in typings/index.d.ts:

  • UpdateLoopObservable (along with its emitted type, UpdateLoop): used to emit a rendering context and time delta within an animation loop.

  • InputObservable (along with its emitted type, GenericInputEvent): used to emit descriptions of user input along with the event data associated with it. The data is generic, meaning that it will need to be provided a type for the data. The type property of this emitted object can be used in type guards to infer the type of the value of the data property.

Static files

We still have only 2 files concerning static data, the public/index.html and public/main.css:

  • In the HTML file ui-block and ui-button were removed and replaced with a single template element, ui-canvas, which will be used to render the canvas.

  • Likewise, the styles for the previous template elements are removed. The canvas element for the new template has a “portrait” orientation, that is longer in height than width, and has the size and dimension similar to a playing card.

Directory structure

There are now 2 new directories alongside the entrypoint, src/index.ts file:

  • util: the subscriberHandler.ts file has been moved here, and a new file helper.ts is added and contains a handful of utility functions that are reused throughout the code.

  • system: this is the location for code that manages specific operation logic of the app, generally within a particular domain.

Canvas

The primary function of the canvas template is to create a rendering context to draw on and generate a time delta.

  • Once the init function is called, the render loop runs:

    • Firstly, calculates a time delta

    • then, it wipes the canvas

    • and finally, emits the delta and context to an observer.

  • The time delta says how much time as passed since the last loop occurred. This is useful in animations, in order to ensure they’re smooth, and can also be used to calculate accurate time-sensitive changes to state.

  • Ensuring the width and height of the canvas is correct is important as subtle changes can affect the resolution and location of objects drawn onto it.

Input

The input system, defined in src/system/inputSystem.ts, adds a bunch of event listeners to the canvas element. All of the event listeners emit a special object to an observer. The enumerables in this file are abstractions on top of the normal event names, while they are also used to separate the type property values such that a MouseInput type will have MouseEvent data, and a TouchInput type will have TouchEvent data. This information is already known in the event listener callback, but can be forgotten once passed to a different context. This system of typing is required so the receiving context can retain the knowledge.

Notice how the class is an observer for the UICanvas element. This is why I regard it as a system, because it manages smaller “components” of data within the application and it performs logic upon them, pertaining to a specific “domain”.

Rendering

The render.ts file is placed alongside the index.ts file in order to emphasise the primary focus of this boilerplate on this particular class. The render class could be considered a system, however, just as index.ts is an entrypoint for the application, the render.ts file is a kind of entrypoint for further exploration.

The render class observes two types of data:

  • UserInputEvent: it receives this whenever a mouse or touch event occurs (as handled by the src/system/inputSystem.ts file), and passes it onto the input method, which then calls the correct handler.

  • UpdateLoop: when the canvas animation loop runs, this method receives a reference to the 2D rendering context, and the time delta. This data is passed to the draw method, which uses the class instance’s state to render a sequence of lines.

The input events affect the state, while the draw calls cause the state to be transformed into graphics. The end result: our interactive graphics. Lines can be drawn by mouse or touch input upon the canvas surface. The use of the time delta passed by the update loop is demonstrated by the rate and amount the hue changes for each separate line.

Before next steps

With this boilerplate, it is now possible to quickly build upon the components and structure to generate a large variety of web applications using interactive graphics.

To view this code on the Internet, as demonstrated in the earlier post (if you have set up Github pages with your repository):

  • Build the code with npm run build.

  • Push to the main branch to update the UI.

  • It should now show an interactive canvas that renders input events as animated lines drawn upon its surface.

Next steps

Start prototyping, experimenting, and exploring!