tidy(ui): abstract worker logic to module

This commit is contained in:
psychedelicious 2024-08-22 10:13:07 +10:00
parent ee7dafaf57
commit 089bc9c7d8
3 changed files with 65 additions and 40 deletions

View File

@ -4,15 +4,14 @@ import type { AppStore } from 'app/store/store';
import type { SerializableObject } from 'common/types';
import { CanvasFilter } from 'features/controlLayers/konva/CanvasFilter';
import { CanvasStageModule } from 'features/controlLayers/konva/CanvasStageModule';
import { CanvasWorkerModule } from 'features/controlLayers/konva/CanvasWorkerModule.js';
import {
canvasToBlob,
canvasToImageData,
getImageDataTransparency,
getPrefixedId,
nanoid,
previewBlob,
} from 'features/controlLayers/konva/util';
import type { Extents, ExtentsResult, GetBboxTask, WorkerLogMessage } from 'features/controlLayers/konva/worker';
import type { CanvasV2State, GenerationMode, Rect } from 'features/controlLayers/store/types';
import type Konva from 'konva';
import { LRUCache } from 'lru-cache';
@ -48,6 +47,7 @@ export class CanvasManager {
background: CanvasBackground;
filter: CanvasFilter;
stage: CanvasStageModule;
worker: CanvasWorkerModule;
log: Logger;
socket: AppSocket;
@ -61,9 +61,6 @@ export class CanvasManager {
canvasCache = new LRUCache<string, HTMLCanvasElement>({ max: 32 });
generationModeCache = new LRUCache<string, GenerationMode>({ max: 100 });
_worker: Worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module', name: 'worker' });
_tasks: Map<string, { task: GetBboxTask; onComplete: (extents: Extents | null) => void }> = new Map();
constructor(stage: Konva.Stage, container: HTMLDivElement, store: AppStore, socket: AppSocket) {
this.id = getPrefixedId(this.type);
this.path = [this.id];
@ -85,6 +82,7 @@ export class CanvasManager {
});
this.stage = new CanvasStageModule(stage, container, this);
this.worker = new CanvasWorkerModule(this);
this.preview = new CanvasPreview(this);
this.stage.addLayer(this.preview.getLayer());
@ -94,30 +92,6 @@ export class CanvasManager {
this.filter = new CanvasFilter(this);
this._worker.onmessage = (event: MessageEvent<ExtentsResult | WorkerLogMessage>) => {
const { type, data } = event.data;
if (type === 'log') {
if (data.ctx) {
this.log[data.level](data.ctx, data.message);
} else {
this.log[data.level](data.message);
}
} else if (type === 'extents') {
const task = this._tasks.get(data.id);
if (!task) {
return;
}
task.onComplete(data.extents);
this._tasks.delete(data.id);
}
};
this._worker.onerror = (event) => {
this.log.error({ message: event.message }, 'Worker error');
};
this._worker.onmessageerror = () => {
this.log.error('Worker message error');
};
this.stateApi.$transformingEntity.set(null);
this.stateApi.$toolState.set(this.stateApi.getToolState());
this.stateApi.$selectedEntityIdentifier.set(this.stateApi.getState().selectedEntityIdentifier);
@ -134,16 +108,6 @@ export class CanvasManager {
this._isDebugging = false;
}
requestBbox(data: Omit<GetBboxTask['data'], 'id'>, onComplete: (extents: Extents | null) => void) {
const id = nanoid();
const task: GetBboxTask = {
type: 'get_bbox',
data: { ...data, id },
};
this._tasks.set(id, { task, onComplete });
this._worker.postMessage(task, [data.buffer]);
}
arrangeEntities() {
let zIndex = 0;

View File

@ -651,7 +651,7 @@ export class CanvasTransformer {
// We have eraser strokes - we must calculate the bbox using pixel data
const canvas = this.parent.renderer.getCanvas(undefined, { opacity: 1 });
const imageData = canvasToImageData(canvas);
this.manager.requestBbox(
this.manager.worker.requestBbox(
{ buffer: imageData.data.buffer, width: imageData.width, height: imageData.height },
(extents) => {
if (extents) {

View File

@ -0,0 +1,61 @@
import type { SerializableObject } from 'common/types';
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import type { Extents, ExtentsResult, GetBboxTask, WorkerLogMessage } from 'features/controlLayers/konva/worker';
import type { Logger } from 'roarr';
export class CanvasWorkerModule {
id: string;
path: string[];
log: Logger;
manager: CanvasManager;
worker: Worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module', name: 'worker' });
tasks: Map<string, { task: GetBboxTask; onComplete: (extents: Extents | null) => void }> = new Map();
constructor(manager: CanvasManager) {
this.id = getPrefixedId('worker');
this.manager = manager;
this.path = this.manager.path.concat(this.id);
this.log = this.manager.buildLogger(this.getLoggingContext);
this.log.debug('Creating canvas worker');
this.worker.onmessage = (event: MessageEvent<ExtentsResult | WorkerLogMessage>) => {
const { type, data } = event.data;
if (type === 'log') {
if (data.ctx) {
this.log[data.level](data.ctx, data.message);
} else {
this.log[data.level](data.message);
}
} else if (type === 'extents') {
const task = this.tasks.get(data.id);
if (!task) {
return;
}
task.onComplete(data.extents);
this.tasks.delete(data.id);
}
};
this.worker.onerror = (event) => {
this.log.error({ message: event.message }, 'Worker error');
};
this.worker.onmessageerror = () => {
this.log.error('Worker message error');
};
}
requestBbox(data: Omit<GetBboxTask['data'], 'id'>, onComplete: (extents: Extents | null) => void) {
const id = getPrefixedId('bbox_calculation');
const task: GetBboxTask = {
type: 'get_bbox',
data: { ...data, id },
};
this.tasks.set(id, { task, onComplete });
this.worker.postMessage(task, [data.buffer]);
}
getLoggingContext = (): SerializableObject => {
return { ...this.manager.getLoggingContext(), path: this.path.join('.') };
};
}