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.
Firstly, clone the repository, and checkout the canvas branch.
git clone firstname.lastname@example.org:drohen/js-canvas-boilerplate.git
Ensure dependencies are installed, run:
Ensure the code runs in development mode:
There are two new observable interfaces added to this project, defined in
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
typeproperty of this emitted object can be used in type guards to infer the type of the value of the
In the HTML file
ui-buttonwere 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.
There are now 2 new directories alongside the entrypoint,
system: this is the location for code that manages specific operation logic of the app, generally within a particular domain.
The primary function of the canvas template is to create a rendering context to draw on and generate a time delta.
initfunction 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.
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”.
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.tsfile), and passes it onto the
inputmethod, 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
drawmethod, 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.
Start prototyping, experimenting, and exploring!