pan, zoom, rotate, and more with your html canvas.
Quick Demo • Install • Key Features • Quick Start • Development • Basic API Overview
A demonstration of uē-tôo's core functionality.
Note: This library is under active development. Some APIs may change in future releases.
Consider this scenario:
You're building a web application that allows users to draw on a canvas. You have your pen and eraser tools ready. During testing, you notice that users need to zoom in to work on fine details. After implementing zoom functionality, you realize users can't see other parts of the drawing when zoomed in, necessitating a pan feature.
As you add these features, the code becomes increasingly complex, especially when handling different input methods (mouse, touch, trackpad). This is where ue-too
comes in - it handles all the panning and zooming logic, allowing you to focus on your application's core functionality.
Even if you're not building a drawing app, ue-too
is useful for any canvas that requires panning functionality. It works with various frameworks including pixi.js, fabric.js, Konva, vanilla JavaScript canvas API, and even headless canvas in Node.js.
Stackblitz example link: This example demonstrates the basic functionality shown in the Quick Start section.
Additional examples in the devserver
directory show integration with pixi.js, fabric.js, and Konva (incomplete but providing general implementation guidance).
npm install ue-too
import { Board } from "ue-too";
Download the bundled JavaScript (ue-too.js) from the releases page and import it in your project:
import { Board } from "./ue-too.js";
import { Board } from "https://cdn.jsdelivr.net/npm/ue-too@latest/index.mjs";
Note: IIFE format is no longer supported.
This example is based on the MDN documentation for the Canvas API.
You can follow along using CodeSandbox, Stackblitz, or any other online IDE.
Following the MDN example, you'll have a green rectangle in the canvas with this HTML and JavaScript:
HTML:
<canvas id="canvas"></canvas>
JavaScript:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 150, 100);
To add ue-too
functionality:
ue-too
and create a new Board
instance:import { Board } from "ue-too";
const canvas = document.getElementById("canvas");
// remove the ctx constant
// instantiate the board by passing in the canvas element
const board = new Board(canvas);
// comment these out for now
// ctx.fillStyle = "green";
// ctx.fillRect(10, 10, 150, 100);
function draw(timestamp) {
// step the board
board.step(timestamp);
// request the next frame
requestAnimationFrame(draw);
}
// start the animation loop
requestAnimationFrame(draw);
function draw(timestamp) {
// step the board
board.step(timestamp);
// add the rectangle back to the canvas, the drawing steps is the same as the MDN example but we're using the context from the board instance.
board.context.fillStyle = "green";
board.context.fillRect(10, 10, 150, 100);
// request the next frame
requestAnimationFrame(draw);
}
// call the draw function every frame
requestAnimationFrame(draw);
Pan:
Zoom:
requestAnimationFrame
callback after the step
functionBoard
class is designed for minimal setup but offers less flexibilityThe Board
class handles:
All components and utility functions are accessible, allowing you to create your own board implementation without using the requestAnimationFrame
callback method.
For detailed camera control information, refer to the Board Camera section.
This section is for working directly with the library's source code. If you're using the library and need to customize component behavior, skip to the Under the Hood section.
pnpm i
I am using pnpm as the package manager for this project.
Node version 20.11.0 is used for development. (Some of the scripts that I wrote for ci/cd uses node version 20 APIs and is not compatible with 22 (specifically the assert
) I will migrate them to use node version 22 APIs when I have time.)
The dev environment setup for this project is relatively simple. Let me break down the different aspects.
pnpm build
Bundling is done through rollup. There's a rollup.config.js
in charge of that. Every subdirectory in the src
directory gets its own bundled index.js file.pnpm test
There's not a lot of tests right now. Only the core functionalities revolving around the camera are unit tested. The next section I will move on to test is the input state machine.pnpm dev
The devserver
directory contains the current examples of the board. It's sort of like a playground. The more complete example is the in the main.ts
file.pnpm dev:docs
would spin up a docs server serving files from the directory docs-staging
pnpm doc:default
would generate a docs-staging/en
and then pnpm doc:move2prod
would copy the entire docs-staging
to docs
The API documentation has all the APIs listed.
ue-too consists of 3 core components:
Board Camera (viewport)
: This is the core of the cores xD; It's the class that holds the information about the viewport.Camera Input Multiplexer
: This is the part that determines which kind of input should be passed through based on the current condition. This is to support multiple input methods. For example, user input would take precedence over the transition animation input and so on.User Input Interpretation
: This is the part that handles the user input events from the canvas element (pointer, keyboard, touch, etc.), and based on the events determine what the user intentions are.To see detail of each component navigate to the respective readme in the subdirectories.
It's recommended to start with the Board Camera since the other parts are built on top of it.
Below is a diagram showing from the user input to how the camera is updated and everything in the middle.
boardify-pixi
package that contains utility functions for the board to work with pixi.js.boardify-fabric
package that contains utility functions for the board to work with fabric.js.boardify-konva
package that contains utility functions for the board to work with konva.js.