đź“· Building a Camera App in TypeScript

How to build a simple photo app in HTML5, CSS3, and TypeScript

Kenneth Reilly
ITNEXT

--

Introduction

In this article, we’ll look at how to build a simple camera web app in HTML5, CSS3, and TypeScript. The full source code for the project is available here.

TypeScript’s powerful and rich feature set lends itself well to building custom applications from scratch, as the developer can start from a clean and stable environment like node, or as in our case, a modern browser API (both of which include high-performance implementations of a JavaScript engine).

Modern, standards-compliant browsers provide incredibly powerful and flexible APIs for working with the browser engine in various ways, which includes accessing various hardware devices (such as the camera).

Project Configuration

Let’s take a look at the package.json file generated with npm init, along with a clean tsconfig.json to define compiler options:

Project structure with package.json and tsconfig.json files

This project uses no external dependencies aside from node and a TypeScript compiler. The file tsconfig.json instructs the TypeScript compiler to generate ES6 modules and output them to the ./build folder. That wraps up the project configuration, meaning the rest will have to be implemented by hand. While challenging, this is made much easier with type checking and other language features, along with powerful code completion and refactoring tools available in modern development environments such as Visual Studio Code.

Application HTML Structure

The page structure for this simple app is defined in index.html:

index.html with metadata and file imports

This short and sweet HTML file includes the bare minimum required for a decent example app: some Open Graph and other metadata, imports for css/style.css and the module ./build/photobooth.js, and the app structure, which is a main container with video, and a footer with two buttons — one for taking a photo, and the other for switching between device cameras.

Note the inline SVG used for the button icons. By setting the viewBox property on the svg elements to “-1 -1 2 2”, the point coordinate system for the entire box becomes centered between -1 and 1 on each axis. This makes it fairly simple to draw things like circles and chevrons as in the example above, using values such as r=0.6 to indicate 60% of the total span from center to edge.

Application CSS Definitions

The layout and styles for this app are defined in css/style.css:

style.css definitions (minus the button:hover effects)

This file is also short, with most of it fitting into the screenshot aside from the button:hover selectors. For simplicity, a root unit of 16px has been defined for the footer metric, with a footer height of (16px * 7) and a button height of (16px * 5), which results in a 7:5 ratio of footer to button height.

The html, body, and svg icons are set to 100% width and height with zero margin or padding. The video width is set to 100vw, and the height to a value of 100vh minus the footer height. The buttons are centered horizontally and spaced evenly across the footer using CSS3 Flexbox properties.

TypeScript Implementation

Next up are the TypeScript files that contain the actual implementation of the main features of this application, which are:

  1. Preview the live camera output
  2. Switch between forward and rear facing cameras
  3. Take a picture and save it to the local device filesystem

First we’ll look at the file src/types.ts, in which there are a few useful types exported for both convenience and type safety:

The contents of src/types.ts with definitions for various types

Within the file src/types.ts, there is an enum for CameraMode which will be used to select the forward and rear facing cameras, an IButtons interface defining the app buttons, and a Defaults class defining width=640.

Next up is the main application file, src/photobooth.ts:

The PhotoBooth abstract class with static properties and initializers

The PhotoBooth class contains static properties for holding references to these four important components used within the application:

  1. mode: the currently selected CameraMode
  2. buttons: the HTMLButtonElement buttons
  3. canvas: an off-screen canvas used to extract the photo from a live stream
  4. video: an HTMLVideoElement that displays the live camera stream

Also defined is a static init() method, which retrieves DOM references to the buttons to attach click handlers to them and then calls the static method on_enumerate_devices() which in turn begins the camera initialization.

The PhotoBooth class with initialization and feature methods

The method init_camera() initializes the camera by calling the get_media() method to retrieve a Promise<MediaStream> from the browser which matches the criteria defined in constraints, and then passing that Promise to the on_get_media() handler, which in turn sets up the canvas and video objects and sets the stream as the video source. The final initialization tasks of setting the height and width of the canvas and video are placed within the on_video_ready() handler, which is fired by the video element once the browser has finished loading it into the DOM and rendering it on-screen.

The PhotoBooth class showing handlers and feature methods

The last event handler defined in the PhotoBooth class is on_error(), which is used as a generic error handler for Promise objects in the app by attaching them to promise chains via the .catch() method. Also, we have the actual features of the photo app. The first is take_photo() which retrieves a .jpeg image by proxying the video through the off-screen canvas object and then triggering a download via an anchor .click() event. The second is the method switch_cam(), which swaps the CameraMode and re-initializes the camera.

Conclusion

This example project demonstrates how to prototype a simple application concept with just a few lines of HTML5, CSS3, and TypeScript, by leveraging the modern features of these languages and the environments designed to support them. One of the powerful features of TypeScript is the ability to define an application in a very structural way, in which it resembles a well-designed server rack, versus a huge mess of random wires everywhere.

The full source for this application is available here, with a live demo here.

I hope you enjoyed this article and found it useful. If you have any corrections or suggestions, or any other ideas in mind, feel free to leave me a comment.

Thanks for reading!

Kenneth Reilly (8_bit_hacker) is CTO of LevelUP

--

--