We want the canvas to run in different environments like browsers, Node.js, WebWorker, etc. Since different environments provide different functionalities, we referenced Pixi.js's implementation and provide an Adapter
interface along with default BrowserAdapter
and WebWorkerAdapter
for developers to choose from.
export interface Adapter {
createCanvas: (
width?: number,
height?: number,
) => HTMLCanvasElement | OffscreenCanvas;
getDocument: () => Document;
getXMLSerializer: () => XMLSerializer | null;
getDOMParser: () => DOMParser | null;
setCursor: (canvas: Canvas, cursor: Cursor) => void;
splitGraphemes: (s: string) => string[];
requestAnimationFrame: (callback: FrameRequestCallback) => number;
cancelAnimationFrame: (handle: number) => void;
}
The system uses BrowserAdapter
by default. If you need to use other adapters, you can set them using the DOMAdapter.set()
method.
import { DOMAdapter, WebWorkerAdapter } from '@infinite-canvas-tutorial/core';
DOMAdapter.set(WebWorkerAdapter);
Although we don't provide a built-in Node.js adapter, you can refer to the NodeJSAdapter used in SSR unit tests for implementation:
import { DOMAdapter } from '@infinite-canvas-tutorial/core';
const NodeJSAdapter: Adapter = {
createCanvas: (width?: number, height?: number) =>
getCanvas(width ?? 0, height ?? 0), // Use headless-gl and node-canvas
getDocument: () => new JSDOM().window._document, // Use JSDOM
//...
};
DOMAdapter.set(NodeJSAdapter);
Let's look at each method provided by the adapter in detail.
createCanvas
As the name suggests, this method is used to create a <canvas>
-like element. It's called when measuring text, determining if a point is within a path, and other operations.
createCanvas: (width?: number, height?: number) =>
HTMLCanvasElement | OffscreenCanvas;
- In browser environment: uses
document.createElement('canvas')
- In WebWorker environment: uses
OffscreenCanvas
- In Node.js environment: uses headless-gl and node-canvas
getDocument
Gets the current Document
object. Mainly used when exporting SVG with ImageExporter.
getDocument: () => Document;
- In browser environment: uses
document
- In WebWorker environment: not available
- In Node.js environment: uses
JSDOM
getXMLSerializer
Gets the current XMLSerializer
object. Used when exporting SVG with ImageExporter.
getXMLSerializer: () => XMLSerializer | null;
In WebWorker and Node.js environments, you can use @xmldom/xmldom:
import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
getDOMParser
Gets the current DOMParser
object. Used when parsing bitmap fonts in XML format. Bitmap Font Example
getDOMParser: () => DOMParser | null;
setCursor
Sets the mouse cursor style for the canvas.
setCursor: (canvas: Canvas, cursor: Cursor) => void;
- In browser environment: uses
$canvas.style.cursor
- In WebWorker and Node.js environments: not available
splitGraphemes
Splits a string into individual characters, supporting compound characters.
splitGraphemes: (s: string) => string[];
- In browser and WebWorker environments: uses Intl.Segmenter
- In Node.js environment: can use grapheme-splitter
import GraphemeSplitter from 'grapheme-splitter';
splitGraphemes: (s: string) => {
const splitter = new GraphemeSplitter();
return splitter.splitGraphemes(s);
},
requestAnimationFrame
Used for camera animations.
- In browser and WebWorker environments: uses requestAnimationFrame
- In Node.js environment: uses
setTimeout
cancelAnimationFrame
Used to cancel camera animations.
- In browser and WebWorker environments: uses cancelAnimationFrame
- In Node.js environment: uses
clearTimeout