scrawl-canvas
Version:
Responsive, interactive and more accessible HTML5 canvas elements. Scrawl-canvas is a JavaScript library designed to make using the HTML5 canvas element easier, and more fun
132 lines (85 loc) • 3.59 kB
JavaScript
// # Cell-fragment factory
// Create a highly reduced CellFragment which supplies the cell pool
// #### Imports
import { doCreate, λnull, λcloneError, Ωempty } from '../helper/utilities.js';
import { makeState } from './state.js';
import baseMix from '../mixin/base.js';
import cellMix from '../mixin/cell-key-functions.js';
import { getCanvasColorSpace } from '../core/user-interaction.js';
// Shared constants
import { _2D, CANVAS, DISPLAY_P3, LEFT, SRGB, TOP } from '../helper/shared-vars.js';
// Local constants
const T_CELLFRAGMENT = 'CellFragment';
// #### CellFragment constructor
const CellFragment = function (name, colorSpace = SRGB) {
this.name = name;
const element = this.element = document.createElement(CANVAS);
this.engine = element.getContext(_2D, {
willReadFrequently: true,
colorSpace,
});
element.width = 1;
element.height = 1;
const state = this.state = makeState(Ωempty);
state.setStateFromEngine(this.engine);
return this;
};
// #### CellFragment prototype
const P = CellFragment.prototype = doCreate();
P.type = T_CELLFRAGMENT;
// #### Mixins
baseMix(P);
cellMix(P);
// #### Packet/Clone management
// This functionality is disabled for CellFragments objects
P.stringifyFunction = λnull;
P.processPacketOut = λnull;
P.finalizePacketOut = λnull;
P.saveAsPacket = function () {
return `[${this.name}, ${this.type}, ${this.lib}, {}]`
};
P.clone = λcloneError;
// #### Kill functionality
// None required
P.setDimensions = function (w, h) {
this.w = w;
this.h = h;
this.element.width = w;
this.element.height = h;
// Resetting canvas dimensions sets the canvas engine back to system default values
// + As we always require `textAlign` and `textBaseline` to be 'left' and 'top' respectively, we reset them here.
// + `requestCell` will always call this function before releasing a pool cell into the wild.
this.engine.textAlign = LEFT;
this.engine.textBaseline = TOP;
};
P.clearCell = function () {
this.engine.clearRect(0, 0, this.w, this.h);
};
// #### Cell pool
// A number of processes - for instance collision functionality, and applying filters to entitys and groups - require the use of a <canvas> element and its CanvasRenderingContext2D engine. Rather than generate these canvas elements on the fly, we store them in a pool, to help make the code more efficiant.
//
// To use a pool cell, request it using the exposed __requestCell__ function.
//
// IT IS IMPERATIVE that requested cells are released once work with them completes, using the __releaseCell__ function. Failure to do this leads to impaired performance as Javascript creates new canvas elements (often in multiples of 60 per second) which need to be garbage collected by the Javascript engine, thus leading to increasingly shoddy performance the longer the animation runs.
const cellPool = [];
let count = 0;
// `Exported function` - __requestCell__
export const requestCell = function (w = 1, h = 1, colorSpace = SRGB) {
if (!cellPool.length) {
cellPool.push(new CellFragment(`pool_${count++}`, getCanvasColorSpace(colorSpace === DISPLAY_P3)));
}
const c = cellPool.shift();
c.setDimensions(w, h);
c.engine.save();
return c;
};
export const releaseCell = function (...args) {
args.forEach(a => {
if (a && a.type === T_CELLFRAGMENT) {
a.setDimensions(1, 1);
a.engine.restore();
a.state.setStateFromEngine(a.engine);
cellPool.push(a);
}
});
};