Skip to content

Commit

Permalink
Improve chessboard display with custom font and DPI scaling
Browse files Browse the repository at this point in the history
- Add LiSu font for Chinese characters on the chessboard
- Implement device pixel ratio (DPI) scaling for better rendering on high-resolution displays
- Adjust text positioning and styling for better visual appearance
- Include .woff2 files in Vite asset processing
  • Loading branch information
iFwu committed Oct 8, 2024
1 parent a17596a commit bed16bc
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 19 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### 2024-10-08
- 增加 更新日志 显示
- 棋盘显示优化
- 棋子字体使用隶书
- 提升高清屏渲染质量

### 2024-10-07
- 优化 **OpenCV.js** 库加载、使用 `cdn.jsdmirror.com` 替换 `jsdelivr.net`
Expand Down
Binary file added assets/LiSu.woff2
Binary file not shown.
9 changes: 8 additions & 1 deletion src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -616,4 +616,11 @@ dialog button:hover {
.changelog-content h3 { font-size: 1rem; }
.changelog-content h4,
.changelog-content h5,
.changelog-content h6 { font-size: 0.9rem; }
.changelog-content h6 { font-size: 0.9rem; }

@font-face {
font-family: 'LiSu';
src: url('/assets/LiSu.woff2') format('woff2');
font-weight: bold;
font-style: normal;
}
63 changes: 45 additions & 18 deletions src/components/ChessboardDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useEffect, useRef } from 'preact/hooks';
import { PieceType, PieceColor } from '../chessboard/types';
import LiSuFontUrl from '/assets/LiSu.woff2?url';

const pieceMap: { [key: string]: string } = {
k: '将',
Expand Down Expand Up @@ -31,20 +32,31 @@ export function ChessboardDisplay({ fen, bestMove }: ChessboardDisplayProps) {
const [board, setBoard] = useState<(Piece | null)[][]>([]);
const canvasRef = useRef<HTMLCanvasElement>(null);
const [scale, setScale] = useState(1);
const [fontLoaded, setFontLoaded] = useState(false);

useEffect(() => {
const font = new FontFace('LiSu', `url(${LiSuFontUrl})`);
font.load().then(() => {
document.fonts.add(font);
return document.fonts.ready;
}).then(() => {
setFontLoaded(true);
}).catch(error => console.error('Failed to load font:', error));
}, []);

useEffect(() => {
const newBoard = parseFEN(fen);
setBoard(newBoard);
}, [fen]);

useEffect(() => {
if (canvasRef.current) {
if (canvasRef.current && fontLoaded) {
drawChessboard();
if (bestMove) {
drawArrow(bestMove);
}
}
}, [board, bestMove]);
}, [board, bestMove, fontLoaded]);

useEffect(() => {
function handleResize() {
Expand Down Expand Up @@ -98,12 +110,17 @@ export function ChessboardDisplay({ fen, bestMove }: ChessboardDisplayProps) {
const boardWidth = 8 * cellSize + 2 * margin;
const boardHeight = 9 * cellSize + 2 * margin;

// Set canvas size based on scale
canvas.width = boardWidth * scale;
canvas.height = boardHeight * scale;
const dpr = window.devicePixelRatio;
// 设置 Canvas 大小,考虑设备像素比
canvas.width = boardWidth * scale * dpr;
canvas.height = boardHeight * scale * dpr;

// Scale the context
ctx.scale(scale, scale);
// 设置 Canvas 的 CSS 大小
canvas.style.width = `${boardWidth * scale}px`;
canvas.style.height = `${boardHeight * scale}px`;

// 缩放绘图上下文以匹配设备像素比
ctx.scale(dpr * scale, dpr * scale);

// 绘制棋盘背景
ctx.fillStyle = '#f0d9b5';
Expand Down Expand Up @@ -146,12 +163,12 @@ export function ChessboardDisplay({ fen, bestMove }: ChessboardDisplayProps) {
ctx.stroke();

// 绘制楚河汉界
ctx.font = '18px "KaiTi", "楷体", sans-serif';
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.font = '20px "LiSu", sans-serif';
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('楚 河', 2 * cellSize + margin, 4.5 * cellSize + margin);
ctx.fillText('界', 6 * cellSize + margin, 4.5 * cellSize + margin);
ctx.fillText('楚 河', 2 * cellSize + margin, 4.6 * cellSize + margin);
ctx.fillText('界', 6 * cellSize + margin, 4.6 * cellSize + margin);

// 绘制九宫格斜线
ctx.beginPath();
Expand All @@ -171,7 +188,7 @@ export function ChessboardDisplay({ fen, bestMove }: ChessboardDisplayProps) {
function drawCrosshair(x: number, y: number, isEdge: boolean = false) {
if (!ctx) return;
const size = cellSize * 0.15;
const offset = -cellSize * 0.25; // 移动距离
const offset = -cellSize * 0.23; // 移动距离
ctx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
ctx.lineWidth = 1;

Expand Down Expand Up @@ -222,7 +239,7 @@ export function ChessboardDisplay({ fen, bestMove }: ChessboardDisplayProps) {
}

// 绘制坐标标记
ctx.font = '14px Arial';
ctx.font = '11px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

Expand Down Expand Up @@ -265,16 +282,26 @@ export function ChessboardDisplay({ fen, bestMove }: ChessboardDisplayProps) {

// 绘制棋子文字
ctx.fillStyle = piece.color === 'red' ? '#c00000' : '#000000';
ctx.font =
'bold 25px "LiSu", "隶书", "STKaiti", "楷体", "KaiTi", "SimKai", sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = 'bold 22px "LiSu", sans-serif';
const pieceChar = piece.type.toUpperCase();
const pieceSymbol =
piece.color === 'red'
? pieceMap[pieceChar]
: pieceMap[pieceChar.toLowerCase()];
ctx.fillText(pieceSymbol, centerX, centerY - radius * 0.12);

// 保存当前的绘图状态
ctx.save();

// 应用变换:水平拉伸 1.2 倍,垂直不变
ctx.setTransform(1 * dpr * scale, 0, 0, 1.25 * dpr * scale, centerX * dpr * scale, centerY * dpr * scale);

// 绘制文字,注意坐标现在是相对于变换后的原点
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(pieceSymbol, radius * 0.05, radius * 0.2);

// 恢复原始绘图状态
ctx.restore();
}
});
});
Expand Down
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ export default defineConfig({
define: {
'import.meta.env.VITE_GIT_COMMIT_HASH': JSON.stringify(process.env.VITE_GIT_COMMIT_HASH),
},
assetsInclude: ['**/*.woff2'],
});

0 comments on commit bed16bc

Please sign in to comment.