UNPKG

pencil.js

Version:

Nice modular interactive 2D drawing library.

208 lines (183 loc) 5.56 kB
import Container from "@pencil.js/container"; import Position from "@pencil.js/position"; import Vector from "@pencil.js/vector"; import { random } from "@pencil.js/math"; /** * @module OffscreenCanvas */ /** * Off-screen canvas class * @class */ export default class OffScreenCanvas extends Container { /** * Off-screen canvas constructor * @param {Number} [width=1] - Width of the canvas * @param {Number} [height=1] - Height of the canvas * @param {ContainerOptions} [options] - Specific options */ constructor (width = 1, height = 1, options) { super(undefined, options); /** * @type {CanvasRenderingContext2D} */ this.ctx = this.constructor.getDrawingContext(width, height); } /** * Change the behavior for upscaled images, smoothing is good for pictures but bad for pixel-art * @param {Boolean} enable - Should the smoothing be active or not * @return {OffScreenCanvas} Itself */ setImageSmoothing (enable) { this.ctx.imageSmoothingEnabled = enable; return this; } /** * Erase the canvas * @return {OffScreenCanvas} Itself */ clear () { this.ctx.clearRect(0, 0, this.width, this.height); if (this.options.fill) { OffScreenCanvas.setOpacity(this.ctx, this.options.opacity); const { width, height } = this; this.ctx.fillStyle = this.options.fill.toString(this.ctx); this.ctx.fillRect(0, 0, width, height); } return this; } /** * Render a container and its children into the canvas * @return {OffScreenCanvas} Itself */ render () { this.clear(); super.render(this.ctx); return this; } /** * @return {Number} */ get width () { return this.ctx.canvas.width; } /** * @param {Number} width - New width value */ set width (width) { this.ctx.canvas.width = +width; } /** * @return {Number} */ get height () { return this.ctx.canvas.height; } /** * @param {Number} height - New height value */ set height (height) { this.ctx.canvas.height = +height; } /** * Return the whole scene size * @return {Position} */ get size () { return new Position(this.width, this.height); } /** * Return this scene center point * @return {Position} */ get center () { return this.size.divide(2); } /** * Return a random position within the scene * @return {Position} */ getRandomPosition () { return new Position(random(this.width), random(this.height)); } /** * Return the whole canvas as data * @param {VectorDefinition} [vectorDefinition] - Box of data to extract * @return {ImageData} */ getImageData (vectorDefinition) { let vector; if (vectorDefinition) { vector = Vector.from(vectorDefinition); } else { vector = new Vector(undefined, this.size); } this.render(); return this.ctx.getImageData(vector.start.x, vector.start.y, vector.end.x, vector.end.y); } /** * Put data into the canvas * @param {ImageData} imageData - Data to add to the canvas * @param {PositionDefinition} [positionDefinition] - Position of the data */ setImageData (imageData, positionDefinition) { const position = Position.from(positionDefinition); this.ctx.putImageData(imageData, position.x, position.y); } /** * Return an image composed of its content * @param {VectorDefinition} [vectorDefinition] - Box to restrict exported data * @param {String} [type="image/png"] - Data format. Supported format depend on the browser implementation (png or jpeg are the only safe choices) * @return {HTMLImageElement} */ toImage (vectorDefinition, type = "image/png") { let vector; if (vectorDefinition) { vector = Vector.from(vectorDefinition); } else { vector = new Vector(undefined, [this.width, this.height]); } const img = window.document.createElement("img"); const { width, height } = this; const size = vector.getDelta(); this.width = size.x; this.height = size.y; img.width = this.width; img.height = this.height; this.ctx.translate(-vector.start.x, -vector.start.y); this.render(); img.src = this.ctx.canvas.toDataURL(type); this.width = width; this.height = height; return img; } /** * Build a canvas context and returns it * @param {Number} width - Width of the canvas * @param {Number} height - Height of the canvas * @return {CanvasRenderingContext2D} */ static getDrawingContext (width = 1, height = 1) { const canvas = window.document.createElement("canvas"); canvas.width = width; canvas.height = height; return canvas.getContext("2d"); } /** * @typedef {Object} OffscreenCanvasOptions * @prop {String|Color} [fill=null] - Background color * @prop {Number} [opacity=1] - Global opacity */ /** * @type {OffscreenCanvasOptions} */ static get defaultOptions () { return { ...super.defaultOptions, fill: null, opacity: 1, }; } }