78 lines
1.7 KiB
TypeScript
78 lines
1.7 KiB
TypeScript
import { storeHex, to1D } from '../../common/convert';
|
|
import { CanvasRecord } from '../../common/types/canvas';
|
|
import { History } from './history';
|
|
import { Imager } from './imager';
|
|
import { config } from '../config';
|
|
|
|
export class Canvas {
|
|
private _fn?: (change: CanvasRecord) => void;
|
|
private _canvas!: Uint32Array;
|
|
private _imager = new Imager(
|
|
this.size,
|
|
config.persistence?.filename,
|
|
config.persistence?.debounce,
|
|
config.persistence?.forcedInterval,
|
|
);
|
|
|
|
public history = new History(config.persistence?.placeStorage);
|
|
|
|
constructor(public size = 1000) {}
|
|
|
|
public async initialize(): Promise<void> {
|
|
this._imager.registerGetCanvas(() => this._canvas);
|
|
|
|
await this.history.initialize();
|
|
|
|
const image = await this._imager.load();
|
|
if (!image) {
|
|
this._canvas = new Uint32Array(this.size * this.size).fill(0xffffff);
|
|
return;
|
|
}
|
|
this._canvas = image;
|
|
}
|
|
|
|
public setPixelAt(
|
|
pixel: string | number,
|
|
x: number,
|
|
y: number,
|
|
user: string,
|
|
) {
|
|
if (x > this.size || y > this.size || x < 0 || y < 0) {
|
|
return;
|
|
}
|
|
|
|
const color = typeof pixel === 'string' ? storeHex(pixel) : pixel;
|
|
const index = to1D(x, y, this.size);
|
|
|
|
// prevent duplicate writes
|
|
if (this._canvas[index] === color) {
|
|
return;
|
|
}
|
|
|
|
const record = {
|
|
user,
|
|
color,
|
|
x,
|
|
y,
|
|
ts: Date.now(),
|
|
};
|
|
|
|
this.history.insert(record);
|
|
this._canvas[index] = color;
|
|
|
|
if (this._fn) {
|
|
this._fn(record);
|
|
}
|
|
|
|
this._imager.save();
|
|
}
|
|
|
|
public getFullPlane(): Uint32Array {
|
|
return this._canvas;
|
|
}
|
|
|
|
public registerChangeHandler(handler: (change: CanvasRecord) => void) {
|
|
this._fn = handler;
|
|
}
|
|
}
|