generated from gxc-solutions/gxc-template-repo
148 lines
4.7 KiB
TypeScript
148 lines
4.7 KiB
TypeScript
import {
|
|
DrawLeafs,
|
|
IBaseFill,
|
|
IDrawNode,
|
|
IEllipseDrawObject,
|
|
IImageDrawObject,
|
|
IRectangleDrawObject,
|
|
IRenderer,
|
|
IScene,
|
|
ITextDrawObject,
|
|
} from "@gxc-solutions/renderer-base/interfaces";
|
|
import {
|
|
isDrawNode,
|
|
isEllipseDrawObject,
|
|
isImageDrawObject,
|
|
isRectangleDrawObject,
|
|
isTextDrawObject,
|
|
} from "@gxc-solutions/renderer-base/utils/draw-object";
|
|
import { Artist } from "./artist";
|
|
import { degToRad } from "@gxc-solutions/math";
|
|
|
|
export class Canvas2DRenderer implements IRenderer {
|
|
public readonly type = "2d";
|
|
|
|
private _context: CanvasRenderingContext2D;
|
|
private _artist: Artist;
|
|
|
|
get holder() {
|
|
return this._canvas;
|
|
}
|
|
|
|
constructor(private _canvas: HTMLCanvasElement) {
|
|
this._context = this._canvas.getContext("2d");
|
|
this._artist = new Artist(this._context);
|
|
}
|
|
|
|
public async render(scene: IScene): Promise<void> {
|
|
this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
|
|
this.renderBg(scene.background);
|
|
scene.static.forEach((leaf) => this.drawLeaf(leaf));
|
|
this.renderNode(scene.node);
|
|
this.renderNode(scene.selection);
|
|
}
|
|
|
|
renderBg(fill: IBaseFill) {
|
|
this._context.save();
|
|
this._artist.setFill(fill);
|
|
this._context.fillRect(0, 0, this._canvas.width, this._canvas.height);
|
|
this._context.restore();
|
|
}
|
|
|
|
renderNode(drawNode: IDrawNode) {
|
|
drawNode.children.forEach((leaf) => {
|
|
if (isDrawNode(leaf)) {
|
|
this._artist.setTransform(leaf.transform);
|
|
this._context.save();
|
|
this.renderNode(leaf);
|
|
this._context.restore();
|
|
}
|
|
this.drawLeaf(leaf as DrawLeafs);
|
|
});
|
|
}
|
|
|
|
private drawLeaf(leaf: DrawLeafs) {
|
|
if (isEllipseDrawObject(leaf)) {
|
|
this._context.save();
|
|
const dn = leaf as IEllipseDrawObject;
|
|
this._context.globalAlpha = dn.opacity;
|
|
this._context.globalCompositeOperation = dn.blendMode as GlobalCompositeOperation;
|
|
this._artist.setTransform(dn.transform);
|
|
this._artist.setFill(dn.fill);
|
|
this._context.ellipse(
|
|
dn.ellipse.center.x - dn.ellipse.radiusX,
|
|
dn.ellipse.center.y - dn.ellipse.radiusY,
|
|
dn.ellipse.radiusX,
|
|
dn.ellipse.radiusY,
|
|
degToRad(0),
|
|
0,
|
|
degToRad(360),
|
|
);
|
|
this._context.fill();
|
|
this._artist.setStroke(dn.stroke);
|
|
if (dn.stroke.width > 0) {
|
|
this._context.stroke();
|
|
}
|
|
this._context.restore();
|
|
}
|
|
if (isImageDrawObject(leaf)) {
|
|
this._context.save();
|
|
const dn = leaf as IImageDrawObject;
|
|
this._context.globalAlpha = dn.opacity;
|
|
this._context.globalCompositeOperation = dn.blendMode as GlobalCompositeOperation;
|
|
this._artist.setTransform(dn.transform);
|
|
|
|
if (dn.source instanceof HTMLImageElement) {
|
|
this._artist.drawImageElement(
|
|
dn.source,
|
|
{ x: dn.rectangle.x, y: dn.rectangle.y },
|
|
{ width: dn.rectangle.width, height: dn.rectangle.height },
|
|
);
|
|
} else if (dn.source instanceof ImageBitmap) {
|
|
this._artist.drawImageBitmap(
|
|
dn.source,
|
|
{ x: dn.rectangle.x, y: dn.rectangle.y },
|
|
{ width: dn.rectangle.width, height: dn.rectangle.height },
|
|
);
|
|
} else if (dn.source instanceof ImageData) {
|
|
this._artist.drawImageData(
|
|
dn.source,
|
|
{ x: dn.rectangle.x, y: dn.rectangle.y },
|
|
{ width: dn.rectangle.width, height: dn.rectangle.height },
|
|
);
|
|
}
|
|
|
|
this._context.restore();
|
|
}
|
|
if (isRectangleDrawObject(leaf)) {
|
|
this._context.save();
|
|
const dn = leaf as IRectangleDrawObject;
|
|
this._context.globalAlpha = dn.opacity;
|
|
this._context.globalCompositeOperation = dn.blendMode as GlobalCompositeOperation;
|
|
this._artist.setTransform(dn.transform);
|
|
this._artist.setFill(dn.fill);
|
|
this._context.fillRect(dn.rectangle.x, dn.rectangle.y, dn.rectangle.width, dn.rectangle.height);
|
|
this._artist.setStroke(dn.stroke);
|
|
if (dn.stroke.width > 0) {
|
|
this._context.strokeRect(dn.rectangle.x, dn.rectangle.y, dn.rectangle.width, dn.rectangle.height);
|
|
}
|
|
this._context.restore();
|
|
}
|
|
if (isTextDrawObject(leaf)) {
|
|
this._context.save();
|
|
const dn = leaf as ITextDrawObject;
|
|
this._context.globalAlpha = dn.opacity;
|
|
this._context.globalCompositeOperation = dn.blendMode as GlobalCompositeOperation;
|
|
this._artist.setTransform(dn.transform);
|
|
this._artist.setStroke(dn.textStroke);
|
|
this._artist.setFont(dn.font);
|
|
const metrics = this._context.measureText(dn.text);
|
|
console.warn(metrics);
|
|
if (dn.textStroke.width > 0) {
|
|
this._context.strokeText(dn.text, dn.rectangle.x, dn.rectangle.y);
|
|
}
|
|
this._context.fillText(dn.text, dn.rectangle.x, dn.rectangle.y);
|
|
this._context.restore();
|
|
}
|
|
}
|
|
}
|