WIP
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { Move } from "chess.js";
|
||||
import { Style, BoardData } from "../types";
|
||||
import drawSquare from "./layers/drawSquare";
|
||||
import drawBorder from "./layers/drawBorder";
|
||||
import drawRectangle from "./layers/drawRectangle";
|
||||
import drawCoords from "./layers/drawCoords";
|
||||
import drawMoveIndicators from "./layers/drawMoveIndicators";
|
||||
import drawPieces from "./layers/drawPieces";
|
||||
import drawHeader from "./layers/drawHeader.ts";
|
||||
import drawExtraInfo from "./layers/drawExtraInfo";
|
||||
import boards from "./styles-board";
|
||||
|
||||
class Board {
|
||||
@@ -24,6 +24,9 @@ class Board {
|
||||
private innerSize: number = 672;
|
||||
private borderWidth: number = 24;
|
||||
private background: Promise<ImageBitmap> | null = null;
|
||||
private extraInfo: boolean = true;
|
||||
private scale: number = 1;
|
||||
private margin: number = 0;
|
||||
|
||||
constructor(private tiles: number = 8) {
|
||||
const ctx = this.canvas.getContext("2d");
|
||||
@@ -41,10 +44,13 @@ class Board {
|
||||
|
||||
setSize(size: number) {
|
||||
this.size = size;
|
||||
this.scale = size / 720;
|
||||
this.margin = this.extraInfo ? 50 * this.scale : 0;
|
||||
|
||||
this.canvas.width = size;
|
||||
this.canvas.height = size;
|
||||
this.canvas.height = size + this.margin * 2;
|
||||
this.tempCanvas.width = size;
|
||||
this.tempCanvas.height = size;
|
||||
this.tempCanvas.height = size + this.margin * 2;
|
||||
|
||||
const tempBorderWidth = this.borderVisible ? this.size / 32 : 0;
|
||||
const tempInnerSize = this.size - tempBorderWidth * 2;
|
||||
@@ -106,33 +112,32 @@ class Board {
|
||||
return color === "w" ? "b" : "w";
|
||||
}
|
||||
|
||||
async renderTitleScreen(header: { [key: string]: string | undefined }) {
|
||||
await drawHeader(this.tempCtx, this.size, this.style, header, this.flipped);
|
||||
this.ctx.drawImage(this.tempCanvas, 0, 0);
|
||||
async titleFrame(header: { [key: string]: string | undefined }) {
|
||||
await drawHeader(
|
||||
this.tempCtx,
|
||||
this.size,
|
||||
this.scale,
|
||||
this.margin,
|
||||
this.style,
|
||||
header,
|
||||
this.flipped
|
||||
);
|
||||
}
|
||||
|
||||
async renderBackground() {
|
||||
const { background, dark, light, border, coords } = this.style;
|
||||
|
||||
await drawSquare(
|
||||
await drawRectangle(this.tempCtx, this.width, this.height, 0, 0, border);
|
||||
|
||||
await drawRectangle(
|
||||
this.tempCtx,
|
||||
this.innerSize,
|
||||
this.innerSize,
|
||||
this.borderVisible ? this.borderWidth : 0,
|
||||
this.borderVisible ? this.borderWidth : 0,
|
||||
(this.borderVisible ? this.borderWidth : 0) + this.margin,
|
||||
background
|
||||
);
|
||||
|
||||
if (this.borderVisible) {
|
||||
await drawBorder(
|
||||
this.tempCtx,
|
||||
this.size - this.borderWidth,
|
||||
this.borderWidth / 2,
|
||||
this.borderWidth / 2,
|
||||
this.borderWidth,
|
||||
border
|
||||
);
|
||||
}
|
||||
|
||||
for (let rank = 0; rank < this.tiles; rank++) {
|
||||
for (let file = 0; file < this.tiles; file++) {
|
||||
const style =
|
||||
@@ -142,9 +147,16 @@ class Board {
|
||||
: dark;
|
||||
|
||||
const x = file * this.squareSize + this.borderWidth;
|
||||
const y = rank * this.squareSize + this.borderWidth;
|
||||
const y = rank * this.squareSize + this.borderWidth + this.margin;
|
||||
|
||||
await drawSquare(this.tempCtx, this.squareSize, x, y, style);
|
||||
await drawRectangle(
|
||||
this.tempCtx,
|
||||
this.squareSize,
|
||||
this.squareSize,
|
||||
x,
|
||||
y,
|
||||
style
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,13 +168,18 @@ class Board {
|
||||
this.flipped,
|
||||
this.borderWidth,
|
||||
this.size,
|
||||
this.borderVisible
|
||||
this.borderVisible,
|
||||
this.margin
|
||||
);
|
||||
|
||||
this.background = createImageBitmap(this.tempCanvas);
|
||||
}
|
||||
|
||||
async render(boardData: BoardData | null, move: Move | null = null) {
|
||||
async frame(
|
||||
boardData: BoardData | null,
|
||||
header: { [key: string]: string | undefined },
|
||||
move: Move | null = null
|
||||
) {
|
||||
this.lastMove = move;
|
||||
this.boardData = boardData;
|
||||
|
||||
@@ -190,10 +207,13 @@ class Board {
|
||||
this.style,
|
||||
this.borderWidth,
|
||||
this.tiles,
|
||||
this.flipped
|
||||
this.flipped,
|
||||
this.margin
|
||||
);
|
||||
}
|
||||
|
||||
const piecesShadow = false;
|
||||
|
||||
await drawPieces(
|
||||
this.tempCtx,
|
||||
boardData,
|
||||
@@ -203,10 +223,26 @@ class Board {
|
||||
this.flipped,
|
||||
check,
|
||||
mate,
|
||||
true
|
||||
piecesShadow,
|
||||
this.margin
|
||||
);
|
||||
}
|
||||
|
||||
if (this.extraInfo && header) {
|
||||
await drawExtraInfo(
|
||||
this.tempCtx,
|
||||
this.width,
|
||||
this.height,
|
||||
this.scale,
|
||||
this.margin,
|
||||
this.style,
|
||||
header,
|
||||
this.flipped
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
this.ctx.clearRect(0, 0, this.size, this.size);
|
||||
this.ctx.drawImage(this.tempCanvas, 0, 0);
|
||||
}
|
||||
@@ -223,6 +259,16 @@ class Board {
|
||||
img.src = dataUrl;
|
||||
return img;
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.size + this.margin * 2;
|
||||
}
|
||||
|
||||
toGIF() {}
|
||||
}
|
||||
|
||||
export default Board;
|
||||
|
||||
@@ -10,16 +10,17 @@ const gradientDirs = {
|
||||
const createGradient = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
data: GradientData,
|
||||
size: number,
|
||||
width: number,
|
||||
height: number,
|
||||
x: number,
|
||||
y: number
|
||||
) => {
|
||||
const [dirXStart, dirYStart, dirXStop, dirYStop] = gradientDirs[data.dir];
|
||||
const gradient = ctx.createLinearGradient(
|
||||
x + dirXStart * size,
|
||||
y + dirYStart * size,
|
||||
x + dirXStop * size,
|
||||
y + dirYStop * size
|
||||
x + dirXStart * width,
|
||||
y + dirYStart * height,
|
||||
x + dirXStop * width,
|
||||
y + dirYStop * height
|
||||
);
|
||||
|
||||
const maxIndex = data.colors.length - 1;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { SquareStyle } from "../../types";
|
||||
import createGradient from "../fill/createGradient";
|
||||
import createPattern from "../fill/createPattern";
|
||||
|
||||
const drawBorder = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
size: number,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
squareStyle: SquareStyle
|
||||
) => {
|
||||
const fill = await (squareStyle.type === "solid"
|
||||
? squareStyle.data.color
|
||||
: squareStyle.type === "gradient"
|
||||
? createGradient(ctx, squareStyle.data, size, x, y)
|
||||
: createPattern(ctx, squareStyle.data));
|
||||
|
||||
if (fill === null) {
|
||||
throw new Error("Cannot create canvas fill style");
|
||||
}
|
||||
|
||||
ctx.lineWidth = width;
|
||||
ctx.strokeStyle = fill;
|
||||
ctx.strokeRect(x, y, size, size);
|
||||
};
|
||||
|
||||
export default drawBorder;
|
||||
@@ -11,7 +11,8 @@ const drawCoords = (
|
||||
blackSide: boolean = false,
|
||||
borderWidth: number,
|
||||
size: number,
|
||||
hasBorder: boolean
|
||||
hasBorder: boolean,
|
||||
margin: number
|
||||
) => {
|
||||
const scale = size / 1024;
|
||||
|
||||
@@ -41,9 +42,10 @@ const drawCoords = (
|
||||
: coords.onDark;
|
||||
|
||||
const x = hasBorder ? borderWidth / 2 : offsetA;
|
||||
const y = hasBorder
|
||||
? squareSize * i + borderWidth + squareSize / 2
|
||||
: squareSize * i + offsetA;
|
||||
const y =
|
||||
(hasBorder
|
||||
? squareSize * i + borderWidth + squareSize / 2
|
||||
: squareSize * i + offsetA) + margin;
|
||||
|
||||
ctx.textAlign = hasBorder ? "center" : "left";
|
||||
ctx.fillText(v, x, y);
|
||||
@@ -65,7 +67,7 @@ const drawCoords = (
|
||||
const x = hasBorder
|
||||
? squareSize * i + borderWidth + squareSize / 2
|
||||
: squareSize * i + offsetA;
|
||||
const y = hasBorder ? size - borderWidth / 2 : size - offsetB;
|
||||
const y = (hasBorder ? size - borderWidth / 2 : size - offsetB) + margin;
|
||||
|
||||
ctx.textAlign = hasBorder ? "center" : "left";
|
||||
ctx.fillText(v, x, y);
|
||||
|
||||
108
src/board/layers/drawExtraInfo.ts
Normal file
108
src/board/layers/drawExtraInfo.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { Style } from "./../../types";
|
||||
import drawText from "./drawText";
|
||||
|
||||
const MONTHS = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
const drawExtraInfo = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
width: number,
|
||||
height: number,
|
||||
scale: number,
|
||||
margin: number,
|
||||
style: Style,
|
||||
data: { [key: string]: string | undefined },
|
||||
flipped: boolean,
|
||||
lastMove: boolean = true
|
||||
) => {
|
||||
ctx.fillStyle = style.coords.onBorder;
|
||||
|
||||
const fontSize = 20 * scale;
|
||||
|
||||
const offsetX = (margin - fontSize) / 2;
|
||||
const offsetY = margin / 2;
|
||||
|
||||
if (data.White) {
|
||||
const text =
|
||||
data.White +
|
||||
(data.WhiteElo && data.WhiteElo !== "?" ? ` (${data.WhiteElo})` : "");
|
||||
|
||||
drawText(
|
||||
ctx,
|
||||
text,
|
||||
fontSize,
|
||||
500,
|
||||
offsetX,
|
||||
(flipped ? offsetY : height - offsetY) * scale,
|
||||
"left"
|
||||
);
|
||||
}
|
||||
|
||||
if (data.Black) {
|
||||
const text =
|
||||
data.Black +
|
||||
(data.BlackElo && data.BlackElo !== "?" ? ` (${data.BlackElo})` : "");
|
||||
|
||||
drawText(
|
||||
ctx,
|
||||
text,
|
||||
fontSize,
|
||||
500,
|
||||
offsetX,
|
||||
(flipped ? height - offsetY : offsetY) * scale,
|
||||
"left"
|
||||
);
|
||||
}
|
||||
|
||||
if (lastMove && data.Result) {
|
||||
const [resultWhite, resultBlack] = data.Result.split("-");
|
||||
|
||||
const textWhite =
|
||||
resultWhite === "0"
|
||||
? "Lost: 0"
|
||||
: resultWhite === "1"
|
||||
? "Won: 1"
|
||||
: "Draw: 1/2";
|
||||
|
||||
const textBlack =
|
||||
resultBlack === "0"
|
||||
? "Lost: 0"
|
||||
: resultBlack === "1"
|
||||
? "Won: 1"
|
||||
: "Draw: 1/2";
|
||||
|
||||
drawText(
|
||||
ctx,
|
||||
textWhite,
|
||||
fontSize,
|
||||
500,
|
||||
width - offsetX,
|
||||
(flipped ? offsetY : height - offsetY) * scale,
|
||||
"right"
|
||||
);
|
||||
|
||||
drawText(
|
||||
ctx,
|
||||
textBlack,
|
||||
fontSize,
|
||||
500,
|
||||
width - offsetX,
|
||||
(flipped ? height - offsetY : offsetY) * scale,
|
||||
"right"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default drawExtraInfo;
|
||||
@@ -1,94 +0,0 @@
|
||||
import { Style } from "./../../types";
|
||||
import drawSquare from "../layers/drawSquare";
|
||||
|
||||
const MONTHS = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
const [y, m, d] = date.split(".").map(Number);
|
||||
|
||||
const month = Number.isNaN(m) ? null : MONTHS[m - 1];
|
||||
const day = Number.isNaN(d) || month === null ? null : d;
|
||||
const year = Number.isNaN(y) ? null : y;
|
||||
|
||||
return month && day && year
|
||||
? `${month} ${day}, ${year}`
|
||||
: month && year
|
||||
? `${month} ${year}`
|
||||
: year
|
||||
? String(year)
|
||||
: "";
|
||||
};
|
||||
|
||||
const drawText = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
fontSize: number,
|
||||
fontWeight: number,
|
||||
x: number,
|
||||
y: number,
|
||||
align: CanvasTextAlign
|
||||
) => {
|
||||
ctx.font = `${fontWeight} ${fontSize}px Ubuntu`;
|
||||
ctx.textAlign = align;
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(text, x, y);
|
||||
};
|
||||
|
||||
const drawHeader = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
size: number,
|
||||
style: Style,
|
||||
data: { [key: string]: string | undefined }
|
||||
) => {
|
||||
console.log(data);
|
||||
const scale = size / 720;
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
await drawSquare(ctx, size, 0, 0, style.border);
|
||||
|
||||
ctx.fillStyle = style.coords.onBorder;
|
||||
|
||||
if (data.White) {
|
||||
drawText(ctx, data.White, 36 * scale, 700, size / 2, 200 * scale, "center");
|
||||
}
|
||||
|
||||
drawText(ctx, "vs", 20 * scale, 500, size / 2, 260 * scale, "center");
|
||||
|
||||
if (data.Black) {
|
||||
drawText(ctx, data.Black, 36 * scale, 700, size / 2, 320 * scale, "center");
|
||||
}
|
||||
|
||||
if (data.Date) {
|
||||
drawText(
|
||||
ctx,
|
||||
formatDate(data.Date),
|
||||
20 * scale,
|
||||
500,
|
||||
size / 2,
|
||||
500 * scale,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
if (data.Event) {
|
||||
drawText(ctx, data.Event, 24 * scale, 500, size / 2, 540 * scale, "center");
|
||||
}
|
||||
|
||||
if (data.Site) {
|
||||
drawText(ctx, data.Site, 20 * scale, 500, size / 2, 580 * scale, "center");
|
||||
}
|
||||
};
|
||||
|
||||
export default drawHeader;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Style } from "./../../types";
|
||||
import drawSquare from "../layers/drawSquare";
|
||||
import drawRectangle from "./drawRectangle";
|
||||
import drawText from "./drawText";
|
||||
|
||||
const MONTHS = [
|
||||
"January",
|
||||
@@ -32,31 +33,18 @@ const formatDate = (date: string) => {
|
||||
: "";
|
||||
};
|
||||
|
||||
const drawText = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
fontSize: number,
|
||||
fontWeight: number,
|
||||
x: number,
|
||||
y: number,
|
||||
align: CanvasTextAlign
|
||||
) => {
|
||||
ctx.font = `${fontWeight} ${fontSize}px Ubuntu`;
|
||||
ctx.textAlign = align;
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(text, x, y);
|
||||
};
|
||||
|
||||
const drawHeader = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
size: number,
|
||||
scale: number,
|
||||
margin: number,
|
||||
style: Style,
|
||||
data: { [key: string]: string | undefined },
|
||||
flipped: boolean
|
||||
) => {
|
||||
const scale = size / 720;
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
await drawSquare(ctx, size, 0, 0, style.border);
|
||||
await drawRectangle(ctx, size, size + margin * 2, 0, 0, style.border);
|
||||
// await drawRectangle()
|
||||
|
||||
ctx.fillStyle = style.coords.onBorder;
|
||||
|
||||
@@ -67,7 +55,7 @@ const drawHeader = async (
|
||||
36 * scale,
|
||||
700,
|
||||
size / 2,
|
||||
(flipped ? 100 : size - 100) * scale,
|
||||
(flipped ? 100 : size - 100) * scale + margin,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
@@ -79,7 +67,7 @@ const drawHeader = async (
|
||||
36 * scale,
|
||||
700,
|
||||
size / 2,
|
||||
(flipped ? size - 100 : 100) * scale,
|
||||
(flipped ? size - 100 : 100) * scale + margin,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
@@ -91,7 +79,7 @@ const drawHeader = async (
|
||||
24 * scale,
|
||||
500,
|
||||
size / 2,
|
||||
(size / 2 - (data.Round ? 20 : 0)) * scale,
|
||||
(size / 2 - (data.Round ? 20 : 0)) * scale + margin,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
@@ -103,7 +91,7 @@ const drawHeader = async (
|
||||
24 * scale,
|
||||
500,
|
||||
size / 2,
|
||||
(size / 2 + 20) * scale,
|
||||
(size / 2 + 20) * scale + margin,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
@@ -115,13 +103,21 @@ const drawHeader = async (
|
||||
20 * scale,
|
||||
500,
|
||||
size / 2,
|
||||
450 * scale,
|
||||
450 * scale + margin,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
if (data.Site) {
|
||||
drawText(ctx, data.Site, 20 * scale, 500, size / 2, 480 * scale, "center");
|
||||
drawText(
|
||||
ctx,
|
||||
data.Site,
|
||||
20 * scale,
|
||||
500,
|
||||
size / 2,
|
||||
480 * scale + margin,
|
||||
"center"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Move } from "chess.js";
|
||||
import { Style, SquareStyle } from "../../types";
|
||||
import drawSquare from "./drawSquare";
|
||||
import drawRectangle from "./drawRectangle";
|
||||
|
||||
const FILES = "abcdefghijklmnopqrstuwvxyz";
|
||||
|
||||
@@ -18,15 +18,15 @@ const drawMoveIndicators = async (
|
||||
{ dark, light, moveIndicator }: Style,
|
||||
borderWidth: number,
|
||||
tiles: number,
|
||||
flipped: boolean = false
|
||||
flipped: boolean,
|
||||
margin: number
|
||||
) => {
|
||||
const [x0, y0] = notationToXY(move.from, flipped, tiles);
|
||||
const [x1, y1] = notationToXY(move.to, flipped, tiles);
|
||||
|
||||
const [fromX, fromY, toX, toY] = [
|
||||
...notationToXY(move.from, flipped, tiles),
|
||||
...notationToXY(move.to, flipped, tiles),
|
||||
].map((v) => v * squareSize + borderWidth);
|
||||
const [fromX, fromY, toX, toY] = [x0, y0, x1, y1].map(
|
||||
(v) => v * squareSize + borderWidth
|
||||
);
|
||||
|
||||
let fromStyle;
|
||||
let toStyle;
|
||||
@@ -43,8 +43,8 @@ const drawMoveIndicators = async (
|
||||
toStyle = fromStyle;
|
||||
}
|
||||
|
||||
drawSquare(ctx, squareSize, fromX, fromY, fromStyle);
|
||||
drawSquare(ctx, squareSize, toX, toY, toStyle);
|
||||
drawRectangle(ctx, squareSize, squareSize, fromX, fromY + margin, fromStyle);
|
||||
drawRectangle(ctx, squareSize, squareSize, toX, toY + margin, toStyle);
|
||||
};
|
||||
|
||||
export default drawMoveIndicators;
|
||||
|
||||
@@ -8,10 +8,10 @@ const drawPieces = async (
|
||||
borderWidth: number,
|
||||
tiles: number,
|
||||
flipped: boolean,
|
||||
check?: "b" | "w",
|
||||
mate?: "b" | "w",
|
||||
shadow: boolean = false,
|
||||
blur: boolean = false
|
||||
check: "b" | "w" | undefined,
|
||||
mate: "b" | "w" | undefined,
|
||||
shadow: boolean,
|
||||
margin: number
|
||||
) => {
|
||||
for (let y = 0; y < 8; y++) {
|
||||
for (let x = 0; x < 8; x++) {
|
||||
@@ -26,10 +26,6 @@ const drawPieces = async (
|
||||
|
||||
const filters = [];
|
||||
|
||||
if (blur) {
|
||||
filters.push(`blur(5px)`);
|
||||
}
|
||||
|
||||
if (shadow) {
|
||||
filters.push(
|
||||
`drop-shadow(${squareSize * 0.05}px ${squareSize * 0.05}px ${
|
||||
@@ -51,7 +47,7 @@ const drawPieces = async (
|
||||
ctx.drawImage(
|
||||
img,
|
||||
borderWidth + file * squareSize,
|
||||
borderWidth + rank * squareSize,
|
||||
borderWidth + rank * squareSize + margin,
|
||||
squareSize,
|
||||
squareSize
|
||||
);
|
||||
|
||||
@@ -2,9 +2,10 @@ import { SquareStyle } from "../../types";
|
||||
import createGradient from "../fill/createGradient";
|
||||
import createPattern from "../fill/createPattern";
|
||||
|
||||
const drawSquare = async (
|
||||
const drawRectangle = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
squareSize: number,
|
||||
width: number,
|
||||
height: number,
|
||||
x: number,
|
||||
y: number,
|
||||
squareStyle: SquareStyle
|
||||
@@ -12,7 +13,7 @@ const drawSquare = async (
|
||||
const fill = await (squareStyle.type === "solid"
|
||||
? squareStyle.data.color
|
||||
: squareStyle.type === "gradient"
|
||||
? createGradient(ctx, squareStyle.data, squareSize, x, y)
|
||||
? createGradient(ctx, squareStyle.data, width, height, x, y)
|
||||
: createPattern(ctx, squareStyle.data));
|
||||
|
||||
if (fill === null) {
|
||||
@@ -20,7 +21,7 @@ const drawSquare = async (
|
||||
}
|
||||
|
||||
ctx.fillStyle = fill;
|
||||
ctx.fillRect(x, y, squareSize, squareSize);
|
||||
ctx.fillRect(x, y, width, height);
|
||||
};
|
||||
|
||||
export default drawSquare;
|
||||
export default drawRectangle;
|
||||
16
src/board/layers/drawText.ts
Normal file
16
src/board/layers/drawText.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
const drawText = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
fontSize: number,
|
||||
fontWeight: number,
|
||||
x: number,
|
||||
y: number,
|
||||
align: CanvasTextAlign
|
||||
) => {
|
||||
ctx.font = `${fontWeight} ${fontSize}px Ubuntu`;
|
||||
ctx.textAlign = align;
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(text, x, y);
|
||||
};
|
||||
|
||||
export default drawText;
|
||||
@@ -2,6 +2,12 @@ import { Style } from "../../types";
|
||||
|
||||
const style: Style = {
|
||||
name: "Calm",
|
||||
// background: {
|
||||
// type: "solid",
|
||||
// data: {
|
||||
// color: "transparent",
|
||||
// },
|
||||
// },
|
||||
background: {
|
||||
type: "gradient",
|
||||
data: {
|
||||
|
||||
@@ -9,6 +9,8 @@ const PGN_KEYS_TO_SHORT = {
|
||||
Date: "D",
|
||||
Result: "R",
|
||||
FEN: "F",
|
||||
WhiteElo: "WE",
|
||||
BlackElo: "BE",
|
||||
};
|
||||
|
||||
const PGN_KEYS = Object.keys(PGN_KEYS_TO_SHORT);
|
||||
|
||||
@@ -3,12 +3,12 @@ import GIFLib from "gif.js";
|
||||
class GIF {
|
||||
private gif: GIFLib;
|
||||
|
||||
constructor(size: number, loop: boolean) {
|
||||
constructor(width: number, height: number, loop: boolean) {
|
||||
this.gif = new GIFLib({
|
||||
workers: 2,
|
||||
quality: 10,
|
||||
width: size,
|
||||
height: size,
|
||||
width,
|
||||
height,
|
||||
repeat: loop ? 0 : -1,
|
||||
});
|
||||
}
|
||||
@@ -26,14 +26,14 @@ class GIF {
|
||||
|
||||
render(): Promise<File> {
|
||||
return new Promise((resolve) => {
|
||||
const timestamp = Date.now();
|
||||
this.gif.on("finished", function (blob) {
|
||||
const file = new File([blob], `board.gif`, {
|
||||
const file = new File([blob], `board_${timestamp}.gif`, {
|
||||
type: "image/gif",
|
||||
lastModified: Date.now(),
|
||||
lastModified: timestamp,
|
||||
});
|
||||
|
||||
resolve(file);
|
||||
// resolve(URL.createObjectURL(file));
|
||||
});
|
||||
|
||||
this.gif.render();
|
||||
|
||||
@@ -11,13 +11,16 @@ const createSimpleGIF = async (
|
||||
size: number = 720
|
||||
) => {
|
||||
const game = new Game().loadPGN(pgn);
|
||||
const board = new Board(8).setStyle(style).setSize(size).showBorder();
|
||||
const gif = new GIF(size, true);
|
||||
const board = new Board(8).setStyle(style).setSize(size).hideBorder();
|
||||
const gif = new GIF(board.width, board.height, true);
|
||||
const header = game.getHeader();
|
||||
|
||||
await board.renderTitleScreen(game.getHeader());
|
||||
await board.titleFrame(header);
|
||||
board.render();
|
||||
gif.add(board.toImgElement(), 5000);
|
||||
|
||||
await board.render(game.getBoardData());
|
||||
await board.frame(game.getBoardData(), header);
|
||||
board.render();
|
||||
gif.add(board.toImgElement(), MOVE_TIME);
|
||||
|
||||
while (true) {
|
||||
@@ -27,7 +30,8 @@ const createSimpleGIF = async (
|
||||
break;
|
||||
}
|
||||
|
||||
await board.render(game.getBoardData(), move);
|
||||
await board.frame(game.getBoardData(), header, move);
|
||||
board.render();
|
||||
gif.add(board.toImgElement(), MOVE_TIME);
|
||||
}
|
||||
|
||||
|
||||
26
src/main.ts
26
src/main.ts
@@ -19,9 +19,13 @@ const play = async (board: Board, pgn: string | null, interval: number) => {
|
||||
game.loadPGN(pgn);
|
||||
}
|
||||
|
||||
await board.renderTitleScreen(game.getHeader());
|
||||
await delay(interval * 5);
|
||||
await board.render(game.getBoardData());
|
||||
const header = game.getHeader();
|
||||
|
||||
await board.titleFrame(header);
|
||||
board.render();
|
||||
await board.frame(game.getBoardData(), header);
|
||||
await delay(interval * 3);
|
||||
board.render();
|
||||
|
||||
while (true) {
|
||||
const move = game.next();
|
||||
@@ -30,8 +34,9 @@ const play = async (board: Board, pgn: string | null, interval: number) => {
|
||||
break;
|
||||
}
|
||||
|
||||
await board.frame(game.getBoardData(), header, move);
|
||||
await delay(interval);
|
||||
await board.render(game.getBoardData(), move);
|
||||
board.render();
|
||||
}
|
||||
|
||||
await delay(interval * 5);
|
||||
@@ -50,25 +55,26 @@ const createDownloadLink = async (pgn: string, style: Style) => {
|
||||
console.log(createDownloadLink.name);
|
||||
|
||||
const main = async () => {
|
||||
const style = styles.lila;
|
||||
const style = styles.calm;
|
||||
|
||||
// window.location.hash =
|
||||
// "#QiBEdWtlIEthcmwgLyBDb3VudCBJc291YXJkCkQgMTg1OC4/Py4/PwpFIFBhcmlzClIgMS0wClMgUGFyaXMgRlJBClcgUGF1bCBNb3JwaHkKCmU0IGU1IE5mMyBkNiBkNCBCZzQgZHhlNSBCeGYzIFF4ZjMgZHhlNSBCYzQgTmY2IFFiMyBRZTcgTmMzIGM2IEJnNSBiNSBOeGI1IGN4YjUgQnhiNSsgTmJkNyBPLU8tTyBSZDggUnhkNyBSeGQ3IFJkMSBRZTYgQnhkNysgTnhkNyBRYjgrIE54YjggUmQ4Iw==";
|
||||
|
||||
// const hash = window.location.hash;
|
||||
// const pgn = hash === "" ? null : decompressPGN(hash.slice(1));
|
||||
const pgn = pgns[1];
|
||||
const pgn = pgns[pgns.length - 1];
|
||||
const board = new Board(8).setStyle(style).setSize(720).showBorder();
|
||||
|
||||
$app?.appendChild(board.canvas);
|
||||
|
||||
console.log(pgn);
|
||||
|
||||
play(board, pgn, 1000);
|
||||
const interval = 1000;
|
||||
play(board, pgn, interval);
|
||||
|
||||
// createDownloadLink(pgns[2], style).then((link) => {
|
||||
// document.body.appendChild(link);
|
||||
// });
|
||||
createDownloadLink(pgns[2], style).then((link) => {
|
||||
document.body.appendChild(link);
|
||||
});
|
||||
};
|
||||
|
||||
WebFont.load({
|
||||
|
||||
@@ -3,6 +3,7 @@ body {
|
||||
background-image: url(background.png);
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
text-align: center;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
@@ -161,6 +161,25 @@ Rdc1 Bf6 28. Rc8+ 1-0`,
|
||||
[Annotator "lichess.org"]
|
||||
|
||||
1. b3 Nf6 { A01 Nimzo-Larsen Attack: Indian Variation } 2. Bb2 g6 3. Nc3 Bg7 4. d3 O-O 5. Qd2 d5 6. O-O-O e6 7. Nf3 Nbd7 8. e4 a5 9. exd5 Nxd5 10. Nxd5 exd5 11. Bxg7 Kxg7 12. g3 b5 13. Bg2 a4 14. b4 a3 15. Nd4 c6 16. Nb3 Nf6 17. Nc5 Nd7 18. Rhe1 Nxc5 19. d4 Na4 20. c3 Nb2 21. Kb1 Bf5+ 22. Ka1 Nxd1 23. Qxd1 Qf6 24. Qf3 Rae8 25. g4 Rxe1+ 26. Qd1 Rxd1# { Black wins by checkmate. } 0-1`,
|
||||
|
||||
`[Event "Casual Bullet game"]
|
||||
[Site "https://lichess.org/kF9IVNaR"]
|
||||
[Date "2022.01.20"]
|
||||
[White "MG014"]
|
||||
[Black "caderek"]
|
||||
[Result "0-1"]
|
||||
[UTCDate "2022.01.20"]
|
||||
[UTCTime "05:03:34"]
|
||||
[WhiteElo "1852"]
|
||||
[BlackElo "1370"]
|
||||
[Variant "Standard"]
|
||||
[TimeControl "30+0"]
|
||||
[ECO "A43"]
|
||||
[Opening "Benoni Defense: Old Benoni"]
|
||||
[Termination "Normal"]
|
||||
[Annotator "lichess.org"]
|
||||
|
||||
1. d4 c5 { A43 Benoni Defense: Old Benoni } 2. Nf3 cxd4 3. Qxd4 Nc6 4. Qd1 g6 5. Nc3 Bg7 6. Bf4 e6 7. e3 Nge7 8. Bd3 O-O 9. Qd2 d5 10. O-O-O b6 11. e4 a5 12. exd5 Nxd5 13. Nxd5 exd5 14. Bb5 Bb7 15. Bxc6 Bxc6 16. a3 Qf6 17. Rhe1 Qxb2# { Black wins by checkmate. } 0-1`,
|
||||
];
|
||||
|
||||
export default pgns;
|
||||
|
||||
Reference in New Issue
Block a user