Added first files and dependencies
Some checks failed
CI / build (push) Failing after 16s

This commit is contained in:
Andrey Kernichniy 2026-03-03 22:56:15 +07:00
parent 0e7cb83ff0
commit 47e9cf85b8
6 changed files with 204 additions and 2 deletions

View file

@ -0,0 +1,93 @@
import { degToRad } from "@gxc-solutions/math/functions";
import { IDrawObject, IRenderer, IScene } from "@gxc-solutions/renderer-base/interfaces";
import { SequentialDrawThread } from "./draw-thread";
const drawRotatedRect = (
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
x: number,
y: number,
width: number,
height: number,
angle: number,
color: string,
) => {
context.save();
// переносим систему координат в центр прямоугольника
context.translate(x + width / 2, y + height / 2);
// поворот вокруг центра
context.rotate(degToRad(angle));
// рисуем прямоугольник так, чтобы его центр оказался в (0,0)
context.fillStyle = color;
context.fillRect(-width / 2, -height / 2, width, height);
context.restore();
};
const drawRotatedStrokeRect = (
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
x: number,
y: number,
width: number,
height: number,
angle: number,
color: string,
) => {
context.save(); // сохраняем систему координат
context.translate(x + width / 2, y + height / 2); // переносим начало в центр фигуры
context.rotate(degToRad(angle)); // вращаем систему координат
context.strokeStyle = color;
context.lineWidth = 2;
context.strokeRect(-width / 2, -height / 2, width, height);
context.restore(); // возвращаем всё обратно
};
export class Canvas2DRenderer implements IRenderer {
public readonly type = "2d";
private _context: CanvasRenderingContext2D;
private _thread: SequentialDrawThread<(offscreenCanvas: OffscreenCanvasRenderingContext2D, objects: IDrawObject[]) => void>;
get holder() {
return this._canvas;
}
constructor(private _canvas: HTMLCanvasElement) {
this._context = this._canvas.getContext("2d");
this._thread = new SequentialDrawThread(
(context2d, objects: IDrawObject[]) => {
const canvas = context2d.canvas;
context2d.clearRect(0, 0, canvas.width, canvas.height);
objects.forEach((drawObject) => {
if (drawObject.type === "rectangle-object") {
drawRotatedRect(
context2d,
drawObject.x,
drawObject.y,
drawObject.width,
drawObject.height,
drawObject.angle,
drawObject.color, // TODO в worker не знает про toString()
);
}
});
},
this._canvas.width,
this._canvas.height,
[drawRotatedRect, drawRotatedStrokeRect, degToRad],
);
}
public async render(scene: IScene): Promise<void> {
const bitmap = await this._thread.run([scene.objects]);
const prev = this._context.globalCompositeOperation;
this._context.globalCompositeOperation = "copy";
// Важно: убедись, что размеры совпадают
this._context.drawImage(bitmap, 0, 0, this._canvas.width, this._canvas.height);
this._context.globalCompositeOperation = prev;
// Освобождаем ресурсы
if ("close" in bitmap) bitmap.close();
}
}