basic drawing and initialization
This commit is contained in:
184
canvas.ts
Normal file
184
canvas.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/// <reference types="./global.d.ts" />
|
||||
|
||||
|
||||
import { Constants } from "./geometry/constants.ts";
|
||||
import { Vector } from "./geometry/vector.ts";
|
||||
|
||||
export const init = (opt: IDoodlerOptions) => {
|
||||
window['doodler'] = new Doodler(opt);
|
||||
window['doodler'].init();
|
||||
}
|
||||
|
||||
interface IDoodlerOptions {
|
||||
width: number;
|
||||
height: number;
|
||||
canvas?: HTMLCanvasElement;
|
||||
bg?: string;
|
||||
framerate?: number;
|
||||
}
|
||||
|
||||
type layer = (ctx: CanvasRenderingContext2D, index: number) => void;
|
||||
|
||||
export class Doodler {
|
||||
private ctx: CanvasRenderingContext2D;
|
||||
private _canvas: HTMLCanvasElement;
|
||||
|
||||
private layers: layer[] = [];
|
||||
|
||||
private bg: string;
|
||||
private framerate: number;
|
||||
|
||||
get width() {
|
||||
return this.ctx.canvas.width;
|
||||
}
|
||||
get height() {
|
||||
return this.ctx.canvas.height;
|
||||
}
|
||||
|
||||
constructor({
|
||||
width,
|
||||
height,
|
||||
canvas,
|
||||
bg,
|
||||
framerate
|
||||
}: IDoodlerOptions) {
|
||||
if (!canvas) {
|
||||
canvas = document.createElement('canvas');
|
||||
document.body.append(canvas);
|
||||
}
|
||||
|
||||
this.bg = bg || 'white';
|
||||
this.framerate = framerate || 60;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
this._canvas = canvas;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
console.log(ctx);
|
||||
if (!ctx) throw 'Unable to initialize Doodler: Canvas context not found';
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.startDrawLoop();
|
||||
}
|
||||
|
||||
private timer?: number;
|
||||
private startDrawLoop() {
|
||||
this.timer = setInterval(() => this.draw(), 1000 / this.framerate);
|
||||
}
|
||||
|
||||
private draw() {
|
||||
this.ctx.fillStyle = this.bg;
|
||||
this.ctx.fillRect(0, 0, this.width, this.height);
|
||||
for (const [i, l] of (this.layers || []).entries()) {
|
||||
l(this.ctx, i);
|
||||
}
|
||||
}
|
||||
|
||||
createLayer(layer: layer) {
|
||||
this.layers.push(layer);
|
||||
}
|
||||
|
||||
deleteLayer(layer: layer) {
|
||||
this.layers = this.layers.filter(l => l !== layer);
|
||||
}
|
||||
|
||||
moveLayer(layer: layer, index: number) {
|
||||
let temp = this.layers.filter(l => l !== layer);
|
||||
|
||||
temp = [...temp.slice(0, index), layer, ...temp.slice(index)];
|
||||
|
||||
this.layers = temp;
|
||||
}
|
||||
|
||||
line(start: Vector, end: Vector, style?: IStyle) {
|
||||
this.setStyle(style);
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(start.x, start.y);
|
||||
this.ctx.lineTo(end.x, end.y);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
dot(at: Vector, style?: IStyle) {
|
||||
this.setStyle({ ...style, weight: 1 })
|
||||
this.ctx.beginPath();
|
||||
|
||||
this.ctx.arc(at.x, at.y, style?.weight || 1, 0, Constants.TWO_PI);
|
||||
this.ctx.fill();
|
||||
}
|
||||
drawCircle(at: Vector, radius: number, style?: IStyle) {
|
||||
this.setStyle(style);
|
||||
this.ctx.beginPath();
|
||||
|
||||
this.ctx.arc(at.x, at.y, radius, 0, Constants.TWO_PI);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
fillCircle(at: Vector, radius: number, style?: IStyle) {
|
||||
this.setStyle(style);
|
||||
this.ctx.beginPath();
|
||||
|
||||
this.ctx.arc(at.x, at.y, radius, 0, Constants.TWO_PI);
|
||||
this.ctx.fill();
|
||||
}
|
||||
drawRect(at: Vector, width: number, height: number, style?: IStyle) {
|
||||
this.setStyle(style);
|
||||
this.ctx.strokeRect(at.x, at.y, width, height);
|
||||
}
|
||||
fillRect(at: Vector, width: number, height: number, style?: IStyle) {
|
||||
this.setStyle(style);
|
||||
this.ctx.fillRect(at.x, at.y, width, height);
|
||||
}
|
||||
drawSquare(at: Vector, size: number, style?: IStyle) {
|
||||
this.drawRect(at, size, size, style);
|
||||
}
|
||||
fillSquare(at: Vector, size: number, style?: IStyle) {
|
||||
this.fillRect(at, size, size, style);
|
||||
}
|
||||
drawCenteredRect(at: Vector, width: number, height: number, style?: IStyle) {
|
||||
this.ctx.save();
|
||||
this.ctx.translate(-width / 2, -height / 2);
|
||||
this.drawRect(at, width, height, style);
|
||||
this.ctx.restore();
|
||||
}
|
||||
fillCenteredRect(at: Vector, width: number, height: number, style?: IStyle) {
|
||||
this.ctx.save();
|
||||
this.ctx.translate(-width / 2, -height / 2);
|
||||
this.fillRect(at, width, height, style);
|
||||
this.ctx.restore();
|
||||
}
|
||||
drawCenteredSquare(at: Vector, size: number, style?: IStyle) {
|
||||
this.drawCenteredRect(at, size, size, style);
|
||||
}
|
||||
fillCenteredSquare(at: Vector, size: number, style?: IStyle) {
|
||||
this.fillCenteredRect(at, size, size, style);
|
||||
}
|
||||
|
||||
drawBezier(a: Vector, b: Vector, c: Vector, d: Vector, style?: IStyle) {
|
||||
this.setStyle(style);
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(a.x, a.y);
|
||||
this.ctx.bezierCurveTo(b.x, b.y, c.x, c.y, d.x, d.y);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
setStyle(style?: IStyle) {
|
||||
const ctx = this.ctx;
|
||||
ctx.fillStyle = style?.color || style?.fillColor || 'black';
|
||||
ctx.strokeStyle = style?.color || style?.strokeColor || 'black';
|
||||
|
||||
ctx.lineWidth = style?.weight || 1;
|
||||
}
|
||||
}
|
||||
|
||||
interface IStyle {
|
||||
color?: string;
|
||||
fillColor?: string;
|
||||
strokeColor?: string;
|
||||
weight?: number;
|
||||
}
|
||||
|
||||
interface IDrawable {
|
||||
draw: () => void;
|
||||
}
|
Reference in New Issue
Block a user