Skip to content

feat: Custom Board Dimensions #174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1c8510b
feat: customizable board dimensions
mmaciesowicz Nov 25, 2024
1b86a91
change board height
mmaciesowicz Nov 26, 2024
ab524c5
fixed notation colors for varying board sizes
mmaciesowicz Dec 2, 2024
a255d46
fixed bottom left square color to be black for white orientation for …
mmaciesowicz Dec 2, 2024
04a51bd
fixed piece sizes for varying sized boards
mmaciesowicz Dec 2, 2024
722909c
changed default promotion to be last rank for varying board sizes.
mmaciesowicz Dec 2, 2024
1a20bf2
changed COLUMNS for dynamic columns
mmaciesowicz Dec 3, 2024
611e8e1
updated README documentation
mmaciesowicz Dec 3, 2024
52f9a74
change arrow size for varying boards
mmaciesowicz Dec 3, 2024
d555152
made notation styling dynamic for different sized boards
mmaciesowicz Dec 4, 2024
fa9b8ec
change support to 16x16 boards
mmaciesowicz Dec 5, 2024
68e9124
fix fen checks for varying board sizes
mmaciesowicz Dec 5, 2024
499d32d
fix arrow sizes for varying board sizes
mmaciesowicz Dec 5, 2024
2c2fa51
fixed issue with promotion on larger boards due to double digits in S…
mmaciesowicz Dec 5, 2024
acde8ac
removed error check in expandFenEmptySquares since giving issues with…
mmaciesowicz Dec 5, 2024
cac7e69
created storybook for custom chessboard sizes
mmaciesowicz Dec 5, 2024
a72a50b
remove testing console.log
mmaciesowicz Dec 5, 2024
432c738
functions.ts code cleanup
mmaciesowicz Dec 5, 2024
2cc4472
removed redundant SquareHeight variables
mmaciesowicz Dec 5, 2024
ae46138
Merge branch 'feature/customizable-board-dimensions' of https://githu…
mmaciesowicz Dec 5, 2024
6e2a5ce
removed boardHeight from PromotionDialog
mmaciesowicz Dec 5, 2024
bdb7d26
simplified expandFenEmptySquares in functions.ts
mmaciesowicz Dec 5, 2024
e8a4c24
added error checking board dimensions
mmaciesowicz Dec 5, 2024
e3bbb97
Varying Board Dimensions storybook styling
mmaciesowicz Dec 5, 2024
7cbbd04
fixed typo in readme
mmaciesowicz Dec 5, 2024
8b7fc3a
fixed error with CustomSquare style in Square.tsx
mmaciesowicz Feb 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ For more advanced code usage examples, please see example boards shown in [`Stor
| arePiecesDraggable | boolean: true | [true, false] | Whether or not all pieces are draggable. |
| arePremovesAllowed | boolean: false | [true, false] | Whether or not premoves are allowed. |
| autoPromoteToQueen | boolean: false | [true, false] | Whether or not to automatically promote pawn to queen. |
| boardDimensions | object: { rows: 8, columns: 8 } | integer: 0 < rows, columns <= 16 | Custom board dimensions (for some chess variants). Supports up to a 16x16 board. |
| boardOrientation | string: 'white' | ['white', 'black'] | The orientation of the board, the chosen colour will be at the bottom of the board. |
| boardWidth | number: 560 | | The width of the board in pixels. |
| clearPremovesOnRightClick | boolean: true | [true, false] | If premoves are allowed, whether or not to clear the premove queue on right click. |
Expand Down Expand Up @@ -166,7 +167,7 @@ For more advanced code usage examples, please see example boards shown in [`Stor
| onPieceDragBegin | function: (piece, sourceSquare) => {} | | User function that is run when piece is grabbed to start dragging. |
| onPieceDragEnd | function: (piece, sourceSquare) => {} | | User function that is run when piece is let go after dragging. |
| onPieceDrop | function: (sourceSquare, targetSquare, piece) => true | returns [true, false] | User function that is run when piece is dropped on a square. Must return whether the move was successful or not. This return value does not control whether or not the piece was placed (as that is controlled by the `position` prop) but instead controls premove logic. |
| onPromotionCheck | function: (sourceSquare, targetSquare, piece) => (((piece === "wP" && sourceSquare[1] === "7" && targetSquare[1] === "8") \|\| (piece === "bP" && sourceSquare[1] === "2" && targetSquare[1] === "1")) && Math.abs(sourceSquare.charCodeAt(0) - targetSquare.charCodeAt(0)) <= 1) | returns [true, false] | User function that is run when piece is dropped. Must return whether the move results in a promotion or not. |
| onPromotionCheck | function: (sourceSquare, targetSquare, piece) => (((piece === "wP" && sourceSquare.slice(1,3) === (boardDimensions.rows - 1).toString() && targetSquare.slice(1,3) === (boardDimensions.rows).toString())) \|\| (piece === "bP" && sourceSquare.slice(1,3) === "2" && targetSquare.slice(1,3) === "1")) && Math.abs(sourceSquare.charCodeAt(0) - targetSquare.charCodeAt(0)) <= 1) | returns [true, false] | User function that is run when piece is dropped. Must return whether the move results in a promotion or not. |
| onPromotionPieceSelect | function: (piece, promoteFromSquare, promoteToSquare) => true | returns [true, false] | User function that is run when a promotion piece is selected. Must return whether the move was successful or not. |
| onSquareClick | function: (square, piece) => {} | | User function that is run when a square is clicked. |
| onSquareRightClick | function: (square) => {} | | User function that is run when a square is right clicked. |
Expand Down
23 changes: 17 additions & 6 deletions src/chessboard/components/Arrows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@ import { getRelativeCoords } from "../functions";
import { useChessboard } from "../context/chessboard-context";
import { Arrow } from "../types";


export const Arrows = () => {
const {
arrows,
newArrow,
boardDimensions,
boardOrientation,
boardWidth,

customArrowColor: primaryArrowCollor,
} = useChessboard();

const boardHeight = (boardWidth * boardDimensions.rows) / boardDimensions.columns;
const squareWidth = boardWidth / boardDimensions.columns;

const arrowsList = [...arrows, newArrow].filter(Boolean) as Arrow[];

return (
<svg
width={boardWidth}
height={boardWidth}
height={boardHeight}
style={{
position: "absolute",
top: "0",
Expand All @@ -30,29 +35,35 @@ export const Arrows = () => {
{arrowsList.map((arrow, i) => {
const [arrowStartField, arrowEndField, arrowColor] = arrow;
if (arrowStartField === arrowEndField) return null;

const from = getRelativeCoords(
boardDimensions,
boardOrientation,
boardWidth,
arrowStartField
);

const to = getRelativeCoords(
boardDimensions,
boardOrientation,
boardWidth,
arrowEndField
);
let ARROW_LENGTH_REDUCER = boardWidth / 32;

let ARROW_LENGTH_REDUCER = squareWidth / 5;

const isArrowActive = i === arrows.length;
// if there are different arrows targeting the same square make their length a bit shorter

if (
arrows.some(
(restArrow) =>
restArrow[0] !== arrowStartField && restArrow[1] === arrowEndField
) &&
!isArrowActive
) {
ARROW_LENGTH_REDUCER = boardWidth / 16;
ARROW_LENGTH_REDUCER = squareWidth / 3.5;
}

const dx = to.x - from.x;
const dy = to.y - from.y;

Expand Down Expand Up @@ -90,7 +101,7 @@ export const Arrows = () => {
opacity={isArrowActive ? "0.5" : "0.65"}
stroke={arrowColor ?? primaryArrowCollor}
strokeWidth={
isArrowActive ? (0.9 * boardWidth) / 40 : boardWidth / 40
isArrowActive ? 0.9 * squareWidth / 5.5 : squareWidth / 5.5
}
markerEnd={`url(#arrowhead-${i})`}
/>
Expand Down
11 changes: 7 additions & 4 deletions src/chessboard/components/Board.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ export function Board() {

const {
boardWidth,
boardDimensions,
clearCurrentRightClickDown,
onPromotionPieceSelect,
setShowPromoteDialog,
showPromoteDialog,
customBoardStyle,
} = useChessboard();

const boardHeight = (boardWidth * boardDimensions.rows) / boardDimensions.columns;

useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (
Expand All @@ -39,7 +42,7 @@ export function Board() {
ref={boardRef}
style={{
position: "relative",
...boardStyles(boardWidth),
...boardStyles(boardWidth, boardHeight),
...customBoardStyle,
}}
>
Expand All @@ -60,7 +63,7 @@ export function Board() {
zIndex: "100",
backgroundColor: "rgba(22,21,18,.7)",
width: boardWidth,
height: boardWidth,
height: boardHeight,
}}
/>
<PromotionDialog />
Expand All @@ -73,8 +76,8 @@ export function Board() {
);
}

const boardStyles = (width: number) => ({
const boardStyles = (width: number, height: number) => ({
cursor: "default",
height: width,
height,
width,
});
31 changes: 19 additions & 12 deletions src/chessboard/components/CustomDragLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,17 @@ export type CustomDragLayerProps = {
};

export function CustomDragLayer({ boardContainer }: CustomDragLayerProps) {
const { boardWidth, chessPieces, id, snapToCursor, allowDragOutsideBoard } =
useChessboard();
const {
boardWidth,
boardDimensions,
chessPieces,
id,
snapToCursor,
allowDragOutsideBoard,
} = useChessboard();

const boardHeight = (boardWidth * boardDimensions.rows) / boardDimensions.columns;
const squareWidth = boardWidth / boardDimensions.columns;

const collectedProps = useDragLayer((monitor) => ({
item: monitor.getItem(),
Expand All @@ -36,19 +45,21 @@ export function CustomDragLayer({ boardContainer }: CustomDragLayerProps) {
if (!clientOffset || !sourceClientOffset) return { display: "none" };

let { x, y } = snapToCursor ? clientOffset : sourceClientOffset;
const halfSquareWidth = boardWidth / 8 / 2;
const halfSquareWidth = squareWidth / 2;

if (snapToCursor) {
x -= halfSquareWidth;
y -= halfSquareWidth;
}

if (!allowDragOutsideBoard) {
const { left, top } = boardContainer;
// half square so the piece reaches the board

const maxLeft = left - halfSquareWidth;
const maxTop = top - halfSquareWidth;
const maxRight = left + boardWidth - halfSquareWidth;
const maxBottom = top + boardWidth - halfSquareWidth;
const maxBottom = top + boardHeight - halfSquareWidth;

x = Math.max(maxLeft, Math.min(x, maxRight));
y = Math.max(maxTop, Math.min(y, maxBottom));
}
Expand All @@ -61,7 +72,7 @@ export function CustomDragLayer({ boardContainer }: CustomDragLayerProps) {
touchAction: "none",
};
},
[boardWidth, allowDragOutsideBoard, snapToCursor, boardContainer]
[squareWidth, boardWidth, boardHeight, allowDragOutsideBoard, snapToCursor, boardContainer]
);

return isDragging && item.id === id ? (
Expand All @@ -77,15 +88,11 @@ export function CustomDragLayer({ boardContainer }: CustomDragLayerProps) {
<div style={getItemStyle(clientOffset, sourceClientOffset)}>
{typeof chessPieces[item.piece] === "function" ? (
(chessPieces[item.piece] as CustomPieceFn)({
squareWidth: boardWidth / 8,
squareWidth,
isDragging: true,
})
) : (
<svg
viewBox={"1 1 43 43"}
width={boardWidth / 8}
height={boardWidth / 8}
>
<svg viewBox={"1 1 43 43"} width={squareWidth} height={squareWidth}>
<g>{chessPieces[item.piece] as ReactNode}</g>
</svg>
)}
Expand Down
Loading