WIP script to generate PNG images from board configs
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
import { BoardConfig, Header, Position } from "./../types";
|
||||
import { Style, BoardStyle } from "../types";
|
||||
import {
|
||||
BoardConfig,
|
||||
CreateCanvas,
|
||||
Header,
|
||||
LoadImage,
|
||||
Position,
|
||||
Style,
|
||||
BoardStyle,
|
||||
} from "./../types";
|
||||
// @ts-ignore
|
||||
import drawRectangle from "./layers/drawRectangle";
|
||||
import drawCoords from "./layers/drawCoords";
|
||||
import drawMoveIndicators from "./layers/drawMoveIndicators";
|
||||
@@ -9,6 +17,7 @@ import drawExtraInfo from "./layers/drawExtraInfo";
|
||||
import boards from "./styles-board/boardStyles";
|
||||
import isLink from "../utils/isLink";
|
||||
import { PiecesStyle } from "./styles-pieces/piecesStyles";
|
||||
import loadImageBrowser from "./loaders/loadImage";
|
||||
|
||||
const defaultConfig: BoardConfig = {
|
||||
size: 720,
|
||||
@@ -62,13 +71,19 @@ class Board {
|
||||
private ctx: CanvasRenderingContext2D;
|
||||
private tempCtx: CanvasRenderingContext2D;
|
||||
|
||||
private tempCanvas: HTMLCanvasElement = document.createElement("canvas");
|
||||
public canvas: HTMLCanvasElement = document.createElement("canvas");
|
||||
private tempCanvas: HTMLCanvasElement;
|
||||
public canvas: HTMLCanvasElement;
|
||||
|
||||
constructor(
|
||||
config: Partial<BoardConfig> = {},
|
||||
private loadImage: LoadImage = loadImageBrowser,
|
||||
private createCanvas: CreateCanvas = () => document.createElement("canvas")
|
||||
) {
|
||||
this.canvas = this.createCanvas();
|
||||
this.tempCanvas = this.createCanvas();
|
||||
|
||||
constructor(config: Partial<BoardConfig> = {}) {
|
||||
const ctx = this.canvas.getContext("2d");
|
||||
const tempCtx = this.tempCanvas.getContext("2d");
|
||||
this.canvas.classList.add("board");
|
||||
|
||||
if (ctx === null || tempCtx === null) {
|
||||
throw new Error("Cannot create canvas 2D context");
|
||||
@@ -94,7 +109,7 @@ class Board {
|
||||
this.cfg = cfg;
|
||||
|
||||
this.setSize(cfg.size);
|
||||
this.setStyle(cfg.boardStyle);
|
||||
this.setStyle(cfg.boardStyle, refresh);
|
||||
|
||||
if (refresh) {
|
||||
await this.refresh();
|
||||
@@ -151,10 +166,12 @@ class Board {
|
||||
this.borderScale = scale;
|
||||
}
|
||||
|
||||
setStyle(style: BoardStyle) {
|
||||
setStyle(style: BoardStyle, refresh: boolean = true) {
|
||||
this.style = boards[style];
|
||||
this.cfg.boardStyle = style;
|
||||
this.refresh();
|
||||
if (refresh) {
|
||||
this.refresh();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -252,12 +269,13 @@ class Board {
|
||||
this.scale,
|
||||
this.margin,
|
||||
this.style,
|
||||
this.getFinalHeader()
|
||||
this.getFinalHeader(),
|
||||
this.loadImage
|
||||
);
|
||||
}
|
||||
|
||||
async renderBackground() {
|
||||
const canvas = document.createElement("canvas");
|
||||
const canvas = this.createCanvas();
|
||||
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||
|
||||
canvas.width = this.size;
|
||||
@@ -265,7 +283,19 @@ class Board {
|
||||
|
||||
const { background, dark, light, border, coords } = this.style;
|
||||
|
||||
await drawRectangle(ctx, this.width, this.height, 0, 0, border);
|
||||
ctx.clearRect(0, 0, this.size, this.size);
|
||||
ctx.fillStyle = "#FF0000";
|
||||
ctx.fillRect(0, 0, this.size, this.size);
|
||||
|
||||
await drawRectangle(
|
||||
ctx,
|
||||
this.width,
|
||||
this.height,
|
||||
0,
|
||||
0,
|
||||
border,
|
||||
this.loadImage
|
||||
);
|
||||
|
||||
await drawRectangle(
|
||||
ctx,
|
||||
@@ -274,6 +304,7 @@ class Board {
|
||||
this.cfg.showBorder ? this.borderWidth : 0,
|
||||
(this.cfg.showBorder ? this.borderWidth : 0) + this.margin,
|
||||
background,
|
||||
this.loadImage,
|
||||
this.cfg.tiles
|
||||
);
|
||||
|
||||
@@ -288,7 +319,15 @@ class Board {
|
||||
const x = file * this.squareSize + this.borderWidth;
|
||||
const y = rank * this.squareSize + this.borderWidth + this.margin;
|
||||
|
||||
await drawRectangle(ctx, this.squareSize, this.squareSize, x, y, style);
|
||||
await drawRectangle(
|
||||
ctx,
|
||||
this.squareSize,
|
||||
this.squareSize,
|
||||
x,
|
||||
y,
|
||||
style,
|
||||
this.loadImage
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,6 +345,7 @@ class Board {
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Background rendered!");
|
||||
this.background = canvas;
|
||||
}
|
||||
|
||||
@@ -331,7 +371,8 @@ class Board {
|
||||
this.borderWidth,
|
||||
this.cfg.tiles,
|
||||
this.cfg.flipped,
|
||||
this.margin
|
||||
this.margin,
|
||||
this.loadImage
|
||||
);
|
||||
}
|
||||
|
||||
@@ -361,7 +402,8 @@ class Board {
|
||||
this.cfg.flipped,
|
||||
this.margin,
|
||||
this.cfg.piecesStyle,
|
||||
this.cfg.showShadows
|
||||
this.cfg.showShadows,
|
||||
this.loadImage
|
||||
);
|
||||
|
||||
if (this.cfg.showExtraInfo && header) {
|
||||
@@ -384,6 +426,55 @@ class Board {
|
||||
this.ctx.drawImage(this.tempCanvas, 0, 0);
|
||||
}
|
||||
|
||||
async renderStatic() {
|
||||
this.ctx.clearRect(0, 0, this.size, this.size);
|
||||
const { background, dark, light, border } = this.style;
|
||||
|
||||
drawRectangle(
|
||||
this.ctx,
|
||||
this.width,
|
||||
this.height,
|
||||
0,
|
||||
0,
|
||||
border,
|
||||
this.loadImage
|
||||
);
|
||||
|
||||
drawRectangle(
|
||||
this.ctx,
|
||||
this.innerSize,
|
||||
this.innerSize,
|
||||
this.cfg.showBorder ? this.borderWidth : 0,
|
||||
(this.cfg.showBorder ? this.borderWidth : 0) + this.margin,
|
||||
background,
|
||||
this.loadImage,
|
||||
this.cfg.tiles
|
||||
);
|
||||
|
||||
for (let rank = 0; rank < this.cfg.tiles; rank++) {
|
||||
for (let file = 0; file < this.cfg.tiles; file++) {
|
||||
const style =
|
||||
(file % 2 === 0 && rank % 2 === 0) ||
|
||||
(file % 2 !== 0 && rank % 2 !== 0)
|
||||
? light
|
||||
: dark;
|
||||
|
||||
const x = file * this.squareSize + this.borderWidth;
|
||||
const y = rank * this.squareSize + this.borderWidth + this.margin;
|
||||
|
||||
drawRectangle(
|
||||
this.ctx,
|
||||
this.squareSize,
|
||||
this.squareSize,
|
||||
x,
|
||||
y,
|
||||
style,
|
||||
this.loadImage
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toImgUrl() {
|
||||
return this.canvas.toDataURL();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Header, Style } from "../../types";
|
||||
import { Header, LoadImage, Style } from "../../types";
|
||||
import drawRectangle from "./drawRectangle";
|
||||
import drawText from "./drawText";
|
||||
import loadImage from "../loaders/loadImage";
|
||||
|
||||
const drawHeader = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -9,10 +8,19 @@ const drawHeader = async (
|
||||
scale: number,
|
||||
margin: number,
|
||||
style: Style,
|
||||
data: Header
|
||||
data: Header,
|
||||
loadImage: LoadImage
|
||||
) => {
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
await drawRectangle(ctx, size, size + margin * 2, 0, 0, style.border);
|
||||
await drawRectangle(
|
||||
ctx,
|
||||
size,
|
||||
size + margin * 2,
|
||||
0,
|
||||
0,
|
||||
style.border,
|
||||
loadImage
|
||||
);
|
||||
|
||||
const font = "Ubuntu";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Solid } from "./../../types";
|
||||
import { Solid, LoadImage } from "./../../types";
|
||||
import { Move } from "chess.js";
|
||||
import { Style, SquareStyle } from "../../types";
|
||||
import drawRectangle from "./drawRectangle";
|
||||
@@ -21,7 +21,8 @@ const drawMoveIndicators = async (
|
||||
borderWidth: number,
|
||||
tiles: number,
|
||||
flipped: boolean,
|
||||
margin: number
|
||||
margin: number,
|
||||
loadImage: LoadImage
|
||||
) => {
|
||||
const [x0, y0] = notationToXY(move.from, flipped, tiles);
|
||||
const [x1, y1] = notationToXY(move.to, flipped, tiles);
|
||||
@@ -62,8 +63,24 @@ const drawMoveIndicators = async (
|
||||
toStyle = fromStyle;
|
||||
}
|
||||
|
||||
drawRectangle(ctx, squareSize, squareSize, fromX, fromY + margin, fromStyle);
|
||||
drawRectangle(ctx, squareSize, squareSize, toX, toY + margin, toStyle);
|
||||
drawRectangle(
|
||||
ctx,
|
||||
squareSize,
|
||||
squareSize,
|
||||
fromX,
|
||||
fromY + margin,
|
||||
fromStyle,
|
||||
loadImage
|
||||
);
|
||||
drawRectangle(
|
||||
ctx,
|
||||
squareSize,
|
||||
squareSize,
|
||||
toX,
|
||||
toY + margin,
|
||||
toStyle,
|
||||
loadImage
|
||||
);
|
||||
};
|
||||
|
||||
export default drawMoveIndicators;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { state } from "../../state";
|
||||
import { Position } from "../../types";
|
||||
import ImagesCache from "../loaders/PiecesCache";
|
||||
import { LoadImage, Position } from "../../types";
|
||||
import PiecesCache from "../loaders/PiecesCache";
|
||||
import { PiecesStyle } from "../styles-pieces/piecesStyles";
|
||||
|
||||
const drawPieces = async (
|
||||
@@ -11,7 +10,8 @@ const drawPieces = async (
|
||||
flipped: boolean,
|
||||
margin: number,
|
||||
piecesStyle: PiecesStyle,
|
||||
shadow: boolean = true
|
||||
shadow: boolean = true,
|
||||
loadImage: LoadImage
|
||||
) => {
|
||||
const { placement, check, mate, turn } = position;
|
||||
ctx.shadowColor = "rgba(0, 0, 0, 0)";
|
||||
@@ -20,7 +20,7 @@ const drawPieces = async (
|
||||
ctx.shadowOffsetY = 0;
|
||||
|
||||
for (const { x, y, type, color } of placement) {
|
||||
const img = await ImagesCache.get(piecesStyle, type, color);
|
||||
const img = await PiecesCache.get(piecesStyle, type, color, loadImage);
|
||||
const rank = flipped ? 8 - 1 - y : y;
|
||||
const file = flipped ? 8 - 1 - x : x;
|
||||
|
||||
@@ -28,7 +28,7 @@ const drawPieces = async (
|
||||
const hex = mate ? "#ff002f" : "#ffa600";
|
||||
|
||||
ctx.shadowColor = hex;
|
||||
ctx.shadowBlur = squareSize * (state.mobile ? 0.15 : 0.15);
|
||||
ctx.shadowBlur = squareSize * 0.15;
|
||||
ctx.shadowOffsetX = 0;
|
||||
ctx.shadowOffsetY = 0;
|
||||
ctx.drawImage(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { SquareStyle } from "../../types";
|
||||
import { LoadImage, SquareStyle } from "../../types";
|
||||
import createGradient from "../fill/createGradient";
|
||||
import loadImage from "../loaders/loadImage";
|
||||
|
||||
const drawRectangle = async (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -9,6 +8,7 @@ const drawRectangle = async (
|
||||
x: number,
|
||||
y: number,
|
||||
squareStyle: SquareStyle,
|
||||
loadImage: LoadImage,
|
||||
tiles: number = 8
|
||||
) => {
|
||||
if (squareStyle.type === "image") {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { PieceType, PieceColor } from "../../types";
|
||||
import { PieceType, PieceColor, LoadImage } from "../../types";
|
||||
import {
|
||||
PiecesStyle,
|
||||
pieceNames,
|
||||
PieceName,
|
||||
} from "../styles-pieces/piecesStyles";
|
||||
import loadImage from "./loadImage";
|
||||
|
||||
let style: PiecesStyle | null = null;
|
||||
let piecesImages: Map<string, HTMLImageElement> = new Map();
|
||||
|
||||
const PiecesCache = {
|
||||
async load(piecesSetName: PiecesStyle) {
|
||||
async load(piecesSetName: PiecesStyle, loadImage: LoadImage) {
|
||||
await Promise.all(
|
||||
pieceNames.map((key) => {
|
||||
const src = `/pieces/${piecesSetName}/${key}.svg`;
|
||||
@@ -24,10 +23,11 @@ const PiecesCache = {
|
||||
async get(
|
||||
piecesSetName: PiecesStyle,
|
||||
pieceName: PieceType,
|
||||
pieceColor: PieceColor
|
||||
pieceColor: PieceColor,
|
||||
loadImage: LoadImage
|
||||
) {
|
||||
if (style !== piecesSetName) {
|
||||
await this.load(piecesSetName);
|
||||
await this.load(piecesSetName, loadImage);
|
||||
style = piecesSetName;
|
||||
}
|
||||
|
||||
@@ -35,23 +35,6 @@ const PiecesCache = {
|
||||
|
||||
return piecesImages.get(piece) as HTMLImageElement;
|
||||
},
|
||||
|
||||
async getDataURLs() {
|
||||
return Promise.all(
|
||||
[...piecesImages.entries()].map(
|
||||
async ([key, img]: [string, HTMLImageElement]) => {
|
||||
let blob = await fetch(img.src).then((r) => r.blob());
|
||||
let dataUrl = await new Promise((resolve) => {
|
||||
let reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
|
||||
return [key, dataUrl];
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default PiecesCache;
|
||||
|
||||
@@ -11,6 +11,7 @@ const piecesStyles = [
|
||||
"cardinal",
|
||||
"cases",
|
||||
"cburnett",
|
||||
"checkers",
|
||||
"chess7",
|
||||
"chessnut",
|
||||
"companion",
|
||||
|
||||
@@ -210,7 +210,7 @@ class Player {
|
||||
}
|
||||
|
||||
if (this.ply > 0 && state.siteConfig.sounds) {
|
||||
state.boardConfig.piecesStyle.includes("anarc")
|
||||
state.boardConfig.piecesStyle.includes("anarchy")
|
||||
? this.playAnarchySFX(position)
|
||||
: this.playSFX(position);
|
||||
}
|
||||
|
||||
@@ -205,3 +205,7 @@ export type Header = {
|
||||
Site: string | null;
|
||||
Result: string | null;
|
||||
};
|
||||
|
||||
export type LoadImage = (src: string) => Promise<HTMLImageElement>;
|
||||
|
||||
export type CreateCanvas = () => HTMLCanvasElement;
|
||||
|
||||
Reference in New Issue
Block a user