Introducing the Canvas 2D Context API for Expo

A pure JS+WebGL implementation of the canvas 2D API

We are excited to announce we’re bringing support for the web’s 2D canvas API to Expo with the npm package ‘expo-2d-context’, a pure-JS art library that can be run on top of both Expo Graphics and a browser WebGL context.

This library strikes a nice balance between a simple no-fuss way to throw some shapes on the screen and a complex toolset for diehard graphics hackers, and is perfect for generative code art or a fledgling programmer’s first video game. With this package, you can use the wealth of pre-existing canvas libraries and tutorials already out there directly in your Expo app.

Basic Usage

Install the npm package, create a GL context by whatever mechanism your environment provides, and then pass it to a new instance of the Expo2DContext class. After that, use said instance as you would in a web browser:

import { GLView } from 'expo';

import Expo2DContext from 'expo-2d-context';

import React from 'react'; export default class App extends React.Component {

render() {

return (

<GLView

style={{ flex: 1 }}

onContextCreate={this._onGLContextCreate}

/>

);

}

_onGLContextCreate = (gl) => {

var ctx = new Expo2DContext(gl);

ctx.translate(50,200)

ctx.scale(4,4) ctx.fillStyle = "grey";

ctx.fillRect(20, 40, 100, 100);

ctx.fillStyle = "white";

ctx.fillRect(30, 100, 20, 30);

ctx.fillRect(60, 100, 20, 30);

ctx.fillRect(90, 100, 20, 30);

ctx.beginPath();

ctx.arc(50,70,18,0,2*Math.PI);

ctx.arc(90,70,18,0,2*Math.PI);

ctx.fill(); ctx.fillStyle = "grey";

ctx.beginPath();

ctx.arc(50,70,8,0,2*Math.PI);

ctx.arc(90,70,8,0,2*Math.PI);

ctx.fill(); ctx.strokeStyle = "black";

ctx.beginPath();

ctx.moveTo(70,40);

ctx.lineTo(70,30);

ctx.arc(70,20,10,0.5*Math.PI,2.5*Math.PI);

ctx.stroke();

ctx.flush();

}

}

Note that unlike normal 2D context implementations, this one assumes it’s drawing within a buffered environment, and thus you need to call the context’s flush() method when you want to actually update the screen.

To use the API’s font drawing functions, first call ctx.initializeText() , which will load the necessary resources. After that, it's business as usual:

await ctx.initializeText()

ctx.fillStyle = “blue”;

ctx.font = “italic 72pt sans-serif”;

ctx.fillText(“Hey Galaxy”, 10, 200);

ctx.flush();

When to use (and not use) expo-2d-context

This library is a great way to draw custom UI elements and ambient animations for your app. It’s also great for simple games and visually interactive applications that also integrate native platform features. That is, it’s good in situations where you want a quick and powerful set of drawing commands but don’t want to create a WebView widget just to scrounge together a DOM with a lone canvas tag. This allows much smoother and responsive interactions between your app’s logic and your rendering code, something WebView-based rendering methods can struggle with.

That said, this implementation is currently slower than a browser’s native 2D context implementation and although its performance should be more than enough for UI and simple video games, those interested in a higher-performance version of this API may prefer to use the WebView rendering engine’s native canvas implementation.

Applications aside, this library will hopefully also serve as a learning tool and alternative implementation to an API that exists mostly only in large rendering engine codebases.

Contributing and testing

To report issues with this library, or help out with its development, check out the repo on github:

https://github.com/expo/expo-2d-context

We use the W3C’s conformance test suite to ensure the library is functioning as expected. A modified version of their test suite sits in the repo’s test directory, and can be run in both browser and Expo environments. For the current state of the test suite, check here:

https://circleci.com/gh/expo/expo-2d-context/tree/master