This commit is contained in:
Maciej Caderek
2022-01-17 04:54:19 +01:00
parent 7052c74171
commit 9482b11319
16 changed files with 140 additions and 86 deletions

View File

@@ -13,20 +13,23 @@ class Board {
private flipped: boolean = false; private flipped: boolean = false;
private boardData: BoardData | null = null; private boardData: BoardData | null = null;
private ctx: CanvasRenderingContext2D; private ctx: CanvasRenderingContext2D;
private tempCtx: CanvasRenderingContext2D;
private borderVisible: boolean = true; private borderVisible: boolean = true;
private lastMove: Move | null = null; private lastMove: Move | null = null;
public canvas: HTMLCanvasElement = document.createElement("canvas"); public canvas: HTMLCanvasElement = document.createElement("canvas");
private tempCanvas: HTMLCanvasElement = document.createElement("canvas");
constructor(private tiles: number = 8) { constructor(private tiles: number = 8) {
this.canvas;
const ctx = this.canvas.getContext("2d"); const ctx = this.canvas.getContext("2d");
const tempCtx = this.tempCanvas.getContext("2d");
this.canvas.classList.add("board"); this.canvas.classList.add("board");
if (ctx == null) { if (ctx === null || tempCtx === null) {
throw new Error("Cannot create canvas 2D context"); throw new Error("Cannot create canvas 2D context");
} }
this.ctx = ctx; this.ctx = ctx;
this.tempCtx = tempCtx;
this.setSize(this.size); this.setSize(this.size);
} }
@@ -34,6 +37,8 @@ class Board {
this.size = size; this.size = size;
this.canvas.width = size; this.canvas.width = size;
this.canvas.height = size; this.canvas.height = size;
this.tempCanvas.width = size;
this.tempCanvas.height = size;
return this; return this;
} }
@@ -86,6 +91,13 @@ class Board {
return color === "w" ? "b" : "w"; return color === "w" ? "b" : "w";
} }
async renderTitleScreen(header: { [key: string]: string | undefined }) {
this.tempCtx.clearRect(0, 0, this.size, this.size);
await drawSquare(this.tempCtx, this.size, 0, 0, this.style.border);
this.ctx.drawImage(this.tempCanvas, 0, 0);
}
async render(boardData: BoardData | null, move: Move | null = null) { async render(boardData: BoardData | null, move: Move | null = null) {
this.lastMove = move; this.lastMove = move;
this.boardData = boardData; this.boardData = boardData;
@@ -106,13 +118,19 @@ class Board {
? this.getOppositeColor(move?.color) ? this.getOppositeColor(move?.color)
: undefined; : undefined;
this.ctx.clearRect(0, 0, this.size, this.size); this.tempCtx.clearRect(0, 0, this.size, this.size);
await drawSquare(this.ctx, innerSize, borderWidth, borderWidth, background); await drawSquare(
this.tempCtx,
innerSize,
borderWidth,
borderWidth,
background
);
if (hasBorder) { if (hasBorder) {
await drawBorder( await drawBorder(
this.ctx, this.tempCtx,
this.size - borderWidth, this.size - borderWidth,
borderWidth / 2, borderWidth / 2,
borderWidth / 2, borderWidth / 2,
@@ -132,12 +150,12 @@ class Board {
const x = file * squareSize + borderWidth; const x = file * squareSize + borderWidth;
const y = rank * squareSize + borderWidth; const y = rank * squareSize + borderWidth;
await drawSquare(this.ctx, squareSize, x, y, style); await drawSquare(this.tempCtx, squareSize, x, y, style);
} }
} }
drawCoords( drawCoords(
this.ctx, this.tempCtx,
coords, coords,
squareSize, squareSize,
this.tiles, this.tiles,
@@ -149,10 +167,10 @@ class Board {
if (boardData !== null) { if (boardData !== null) {
if (this.lastMove) { if (this.lastMove) {
drawMoveIndicators( drawMoveIndicators(
this.ctx, this.tempCtx,
this.lastMove, this.lastMove,
squareSize, squareSize,
moveIndicator, this.style,
borderWidth, borderWidth,
this.tiles, this.tiles,
this.flipped this.flipped
@@ -160,7 +178,7 @@ class Board {
} }
await drawPieces( await drawPieces(
this.ctx, this.tempCtx,
boardData, boardData,
squareSize, squareSize,
borderWidth, borderWidth,
@@ -171,6 +189,9 @@ class Board {
true true
); );
} }
this.ctx.clearRect(0, 0, this.size, this.size);
this.ctx.drawImage(this.tempCanvas, 0, 0);
} }
toImgUrl() { toImgUrl() {

View File

@@ -39,7 +39,12 @@ const drawCoords = (
ctx.font = `${fontSize}px ${FONT_FAMILY}`; ctx.font = `${fontSize}px ${FONT_FAMILY}`;
orderedRanks.forEach((v, i) => { orderedRanks.forEach((v, i) => {
ctx.fillStyle = i % 2 === 0 ? coords.darkColor : coords.lightColor; ctx.fillStyle =
borderWidth > 0
? coords.onBorder
: i % 2 === 0
? coords.onLight
: coords.onDark;
ctx.textAlign = borderWidth > 0 ? "center" : "left"; ctx.textAlign = borderWidth > 0 ? "center" : "left";
ctx.fillText(v, offsetRankX, squareSize * i + fontSize + offsetRankY); ctx.fillText(v, offsetRankX, squareSize * i + fontSize + offsetRankY);
@@ -49,7 +54,12 @@ const drawCoords = (
const orderedFiles = blackSide ? files.reverse() : files; const orderedFiles = blackSide ? files.reverse() : files;
orderedFiles.forEach((v, i) => { orderedFiles.forEach((v, i) => {
ctx.fillStyle = i % 2 === 0 ? coords.lightColor : coords.darkColor; ctx.fillStyle =
borderWidth > 0
? coords.onBorder
: i % 2 === 0
? coords.onDark
: coords.onLight;
ctx.textAlign = borderWidth > 0 ? "center" : "left"; ctx.textAlign = borderWidth > 0 ? "center" : "left";
ctx.fillText( ctx.fillText(

View File

@@ -1,5 +1,5 @@
import { Move } from "chess.js"; import { Move } from "chess.js";
import { SquareStyle } from "../../types"; import { Style, SquareStyle } from "../../types";
import drawSquare from "./drawSquare"; import drawSquare from "./drawSquare";
const FILES = "abcdefghijklmnopqrstuwvxyz"; const FILES = "abcdefghijklmnopqrstuwvxyz";
@@ -15,18 +15,36 @@ const drawMoveIndicators = async (
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,
move: Move, move: Move,
squareSize: number, squareSize: number,
squareStyle: SquareStyle, { dark, light, moveIndicator }: Style,
borderWidth: number, borderWidth: number,
tiles: number, tiles: number,
flipped: boolean = false flipped: boolean = false
) => { ) => {
const [x0, y0] = notationToXY(move.from, flipped, tiles);
const [x1, y1] = notationToXY(move.to, flipped, tiles);
const [fromX, fromY, toX, toY] = [ const [fromX, fromY, toX, toY] = [
...notationToXY(move.from, flipped, tiles), ...notationToXY(move.from, flipped, tiles),
...notationToXY(move.to, flipped, tiles), ...notationToXY(move.to, flipped, tiles),
].map((v) => v * squareSize + borderWidth); ].map((v) => v * squareSize + borderWidth);
drawSquare(ctx, squareSize, fromX, fromY, squareStyle); let fromStyle;
drawSquare(ctx, squareSize, toX, toY, squareStyle); let toStyle;
if (moveIndicator.type === "hueShift") {
ctx.filter = `hue-rotate(${moveIndicator.data}deg)`;
fromStyle = (x0 + y0) % 2 === 0 ? light : dark;
toStyle = (x1 + y1) % 2 === 0 ? light : dark;
} else {
fromStyle = {
type: "solid",
data: { color: moveIndicator.data },
} as SquareStyle;
toStyle = fromStyle;
}
drawSquare(ctx, squareSize, fromX, fromY, fromStyle);
drawSquare(ctx, squareSize, toX, toY, toStyle);
}; };
export default drawMoveIndicators; export default drawMoveIndicators;

View File

@@ -21,10 +21,8 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "hueShift",
data: { data: 70,
color: "#7D3EC155",
},
}, },
border: { border: {
type: "solid", type: "solid",
@@ -33,8 +31,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "#ececa4", onLight: "#72b339",
darkColor: "#ececa4", onDark: "#ececa4",
onBorder: "#ececa4",
}, },
}; };

View File

@@ -22,10 +22,8 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "color",
data: { data: "#ee59ff55",
color: "#0077ff00",
},
}, },
border: { border: {
type: "gradient", type: "gradient",
@@ -35,8 +33,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "rgba(255, 255, 255, 0.9)", onLight: "rgba(0, 0, 0, 0.5)",
darkColor: "rgba(255, 255, 255, 0.9)", onDark: "rgba(255, 255, 255, 0.9)",
onBorder: "rgba(255, 255, 255, 0.9)",
}, },
}; };

View File

@@ -21,10 +21,8 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "color",
data: { data: "#00ffff55",
color: "#0055ff77",
},
}, },
border: { border: {
type: "solid", type: "solid",
@@ -33,8 +31,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "#222", onLight: "#222",
darkColor: "#222", onDark: "#ddd",
onBorder: "#ddd",
}, },
}; };

View File

@@ -2,7 +2,7 @@ import avocado from "./avocado";
import calm from "./calm"; import calm from "./calm";
import standard from "./standard"; import standard from "./standard";
import glass from "./glass"; import glass from "./glass";
// import kittens from "./kittens"; import kittens from "./kittens";
import lichess from "./lichess"; import lichess from "./lichess";
import lila from "./lila"; import lila from "./lila";
import mono from "./mono"; import mono from "./mono";
@@ -12,7 +12,7 @@ export default {
avocado, avocado,
calm, calm,
glass, glass,
// kittens, kittens,
lichess, lichess,
lila, lila,
mono, mono,

View File

@@ -5,26 +5,24 @@ const style: Style = {
background: { background: {
type: "image", type: "image",
data: { data: {
src: "https://placekitten.com/1024/1024", src: "https://placekitten.com/720/720",
}, },
}, },
dark: { dark: {
type: "image", type: "solid",
data: { data: {
src: "https://placekitten.com/128/128", color: "#00000055",
}, },
}, },
light: { light: {
type: "solid", type: "solid",
data: { data: {
color: "transparent", color: "#ffffff55",
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "color",
data: { data: "#ffff0055",
color: "#0055ff77",
},
}, },
border: { border: {
type: "solid", type: "solid",
@@ -33,8 +31,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "#eee", onLight: "#333",
darkColor: "#eee", onDark: "#eee",
onBorder: "#eee",
}, },
}; };

View File

@@ -21,21 +21,19 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "hueShift",
data: 40,
},
border: {
type: "solid", type: "solid",
data: { data: {
color: "rgba(155,199,0,0.41)", color: "#896d56",
}, },
}, },
border: null,
// border: {
// type: "solid",
// data: {
// color: "#896d56",
// },
// },
coords: { coords: {
lightColor: "#f0d9b5", onLight: "#b58863",
darkColor: "#b58863", onDark: "#f0d9b5",
onBorder: "#f0d9b5",
}, },
}; };

View File

@@ -21,10 +21,8 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "hueShift",
data: { data: 180,
color: "#0055ff77",
},
}, },
border: { border: {
type: "solid", type: "solid",
@@ -33,8 +31,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "#e5d0cb", onLight: "#c0acb5",
darkColor: "#e5d0cb", onDark: "#e5d0cb",
onBorder: "#e5d0cb",
}, },
}; };

View File

@@ -21,10 +21,8 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "color",
data: { data: "#00ff0044",
color: "#0055ff77",
},
}, },
border: { border: {
type: "solid", type: "solid",
@@ -33,8 +31,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "#eee", onLight: "#bbb",
darkColor: "#eee", onDark: "#eee",
onBorder: "#eee",
}, },
}; };

View File

@@ -21,16 +21,19 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "hueShift",
data: 330,
},
border: {
type: "solid", type: "solid",
data: { data: {
// color: "#0055ff77", color: "#962c2c",
color: "transparent",
}, },
}, },
border: null,
coords: { coords: {
lightColor: "#ffa987", onLight: "#e54b4b",
darkColor: "#e54b4b", onDark: "#ffa987",
onBorder: "#ffa987",
}, },
}; };

View File

@@ -21,10 +21,8 @@ const style: Style = {
}, },
}, },
moveIndicator: { moveIndicator: {
type: "solid", type: "color",
data: { data: "#0088ff66",
color: "#0055ff55",
},
}, },
border: { border: {
type: "solid", type: "solid",
@@ -33,8 +31,9 @@ const style: Style = {
}, },
}, },
coords: { coords: {
lightColor: "#eee", onLight: "#999",
darkColor: "#eee", onDark: "#eee",
onBorder: "#eee",
}, },
}; };

View File

@@ -78,6 +78,10 @@ class Game {
return this.replay.board(); return this.replay.board();
} }
getHeader() {
return this.replay.header();
}
pgn() { pgn() {
return this.game.pgn(); return this.game.pgn();
} }

View File

@@ -19,6 +19,8 @@ const play = async (board: Board, pgn: string | null, interval: number) => {
} }
// game.goto(28); // game.goto(28);
// await board.renderTitleScreen(game.getHeader());
// await delay(interval);
await board.render(game.getBoardData()); await board.render(game.getBoardData());
while (true) { while (true) {
@@ -46,16 +48,16 @@ const createDownloadLink = async (pgn: string, style: Style) => {
}; };
const main = async () => { const main = async () => {
const style = styles.avocado; const style = styles.calm;
const hash = window.location.hash; const hash = window.location.hash;
const pgn = hash === "" ? null : decompressPGN(hash.slice(1)); const pgn = hash === "" ? null : decompressPGN(hash.slice(1));
const board = new Board(8).setStyle(style).setSize(720).showBorder(); const board = new Board(8).setStyle(style).setSize(720).showBorder();
window.location.hash = "#alala";
$app?.appendChild(board.canvas); $app?.appendChild(board.canvas);
console.log(pgn);
play(board, pgn, 1000); play(board, pgn, 1000);
// createDownloadLink(pgns[0], style).then((link) => { // createDownloadLink(pgns[0], style).then((link) => {

View File

@@ -33,19 +33,24 @@ export type Image = {
}; };
export type Coords = { export type Coords = {
darkColor: string; onLight: string;
lightColor: string; onDark: string;
onBorder: string;
}; };
export type SquareStyle = Gradient | Solid | Image; export type SquareStyle = Gradient | Solid | Image;
export type MoveIndicator =
| { type: "hueShift"; data: number }
| { type: "color"; data: string };
export type Style = { export type Style = {
name: string; name: string;
background: SquareStyle; background: SquareStyle;
light: SquareStyle; light: SquareStyle;
dark: SquareStyle; dark: SquareStyle;
moveIndicator: SquareStyle; moveIndicator: MoveIndicator;
border: SquareStyle | null; border: SquareStyle;
coords: Coords; coords: Coords;
}; };