Allow big symbols

This commit is contained in:
Dylan Pizzo 2025-01-07 20:02:50 -08:00
parent 52db63d395
commit ff5c543147
3 changed files with 82 additions and 14 deletions

View File

@ -9,6 +9,8 @@ export type Piece =
| { | {
type: "symbol"; type: "symbol";
symbol: "coin" | "debt" | "potion" | "vp" | "vp-token"; symbol: "coin" | "debt" | "potion" | "vp" | "vp-token";
isBig?: boolean;
prefix?: string;
text: string; text: string;
textColor: string; textColor: string;
}; };
@ -157,13 +159,21 @@ const symbolPiece = pieceDef({
const metrics = context.measureText(" "); const metrics = context.measureText(" ");
const height = const height =
metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
const prefixMetrics = context.measureText(piece.prefix ?? "");
const coinImage = getImage(piece.symbol); const coinImage = getImage(piece.symbol);
context.restore(); context.restore();
const { isBig } = piece;
const scale = isBig ? 2.5 : 1;
return { return {
type: "content", type: "content",
width: coinImage.width * (height / coinImage.height), width:
ascent: metrics.fontBoundingBoxAscent, scale *
descent: metrics.fontBoundingBoxDescent, (prefixMetrics.width +
coinImage.width * (height / coinImage.height)),
ascent: scale * metrics.fontBoundingBoxAscent,
descent: scale * metrics.fontBoundingBoxDescent,
prefixWidth: scale * prefixMetrics.width,
scale,
}; };
}, },
render(context, piece, x, y, measure) { render(context, piece, x, y, measure) {
@ -173,20 +183,34 @@ const symbolPiece = pieceDef({
// context.fillRect(x, y - measure.ascent, measure.width, height); // context.fillRect(x, y - measure.ascent, measure.width, height);
context.drawImage( context.drawImage(
getImage(piece.symbol), getImage(piece.symbol),
x, x + measure.prefixWidth,
y - measure.ascent, y - measure.ascent,
measure.width, measure.width - measure.prefixWidth,
height height
); );
const prefixFontInfo = parseFont(context.font);
prefixFontInfo.weight = "bold";
prefixFontInfo.size =
parseInt(prefixFontInfo.size.toString()) * measure.scale;
const prefixFont = stringifyFont(prefixFontInfo);
context.font = prefixFont;
context.fillText(piece.prefix ?? "", x, y);
const fontInfo = parseFont(context.font); const fontInfo = parseFont(context.font);
fontInfo.family = ["DominionSpecial"]; fontInfo.family = ["DominionSpecial"];
fontInfo.weight = "bold"; fontInfo.weight = "bold";
fontInfo.size = parseInt(fontInfo.size.toString()) * 1.2; fontInfo.size =
parseInt(fontInfo.size.toString()) * 1.2 * measure.scale;
const font = stringifyFont(fontInfo); const font = stringifyFont(fontInfo);
context.font = font; context.font = font;
context.fillStyle = piece.textColor; context.fillStyle = piece.textColor;
context.textAlign = "center"; context.textAlign = "center";
context.fillText(piece.text, x + measure.width / 2, y); context.fillText(
piece.text,
x + measure.prefixWidth + (measure.width - measure.prefixWidth) / 2,
y
);
context.restore(); context.restore();
}, },
}); });
@ -341,7 +365,11 @@ export const renderDominionText = async (
} }
}; };
export const parse = (text: string): Piece[] => { export const parse = (
text: string,
options?: { isDescription: boolean }
): Piece[] => {
const { isDescription = false } = options ?? {};
const pieces: Piece[] = []; const pieces: Piece[] = [];
const symbolMap = { const symbolMap = {
"$": { symbol: "coin", textColor: "black" }, "$": { symbol: "coin", textColor: "black" },
@ -351,23 +379,28 @@ export const parse = (text: string): Piece[] => {
"#": { symbol: "vp-token", textColor: "black" }, "#": { symbol: "vp-token", textColor: "black" },
} as const; } as const;
for (let i = 0; i < text.length; i++) { for (let i = 0; i < text.length; i++) {
const char = text[i]; const char = text[i]!;
if (char === " ") { if (char === " ") {
pieces.push({ type: "space" }); pieces.push({ type: "space" });
} else if (char === "\n") { } else if (char === "\n") {
pieces.push({ type: "break" }); pieces.push({ type: "break" });
} else if (char && char in symbolMap) { } else if (char in symbolMap) {
const c = char as keyof typeof symbolMap; const c = char as keyof typeof symbolMap;
const end = text.slice(i).match(new RegExp(`\\${c}\\w*`))![0] const end = text.slice(i).match(new RegExp(`\\${c}\\w*`))![0]
.length; .length;
const isBig =
isDescription &&
["\n", undefined].includes(text[i - 1]) &&
["\n", undefined].includes(text[i + end]);
pieces.push({ pieces.push({
type: "symbol", type: "symbol",
...symbolMap[c], ...symbolMap[c],
text: text.slice(i + 1, i + end), text: text.slice(i + 1, i + end),
isBig,
}); });
i += end - 1; i += end - 1;
} else if (char === "+") { } else if (char === "+") {
const match = text.slice(i).match(/\+\d* \w+/); const match = text.slice(i).match(/\+\d*( \w+)?/);
if (match) { if (match) {
const end = match[0].length; const end = match[0].length;
pieces.push({ pieces.push({
@ -389,8 +422,42 @@ export const parse = (text: string): Piece[] => {
text[i + 1] === "\n" text[i + 1] === "\n"
) { ) {
pieces.push({ type: "hr" }); pieces.push({ type: "hr" });
} else if (/\d/.test(char)) {
const match = text.slice(i).match(
new RegExp(
`\\d+(${Object.keys(symbolMap)
.map((s) => `\\${s}`)
.join("|")})`
)
);
if (match) {
const end = match[0].length;
const symbolChar = match[1] as keyof typeof symbolMap;
const isBig =
isDescription &&
["\n", undefined].includes(text[i - 1]) &&
["\n", undefined].includes(text[i + end]);
pieces.push({
type: "symbol",
...symbolMap[symbolChar],
prefix: text.slice(i, i + end - 1),
text: "",
isBig,
});
i += end - 1;
} else {
const end = text.slice(i).match(/\d+/)![0].length;
pieces.push({ type: "text", text: text.slice(i, i + end) });
i += end - 1;
}
} else { } else {
const end = text.slice(i).match(/[^$ \n]+/)![0].length; const end = text.slice(i).match(
new RegExp(
`[^${Object.keys(symbolMap)
.map((s) => `\\${s}`)
.join("")} \n]+`
)
)![0].length;
pieces.push({ type: "text", text: text.slice(i, i + end) }); pieces.push({ type: "text", text: text.slice(i, i + end) });
i += end - 1; i += end - 1;
} }

View File

@ -181,11 +181,12 @@ const drawStandardCard = async (
context.font = "60pt DominionText"; context.font = "60pt DominionText";
await renderDominionText( await renderDominionText(
context, context,
parse(card.description), parse(card.description, { isDescription: true }),
w / 2, w / 2,
1490, 1490,
1000 1000
); );
console.log(card.title, parse(card.description));
// Draw the types // Draw the types
size = 65; size = 65;
context.font = `${size}pt DominionTitle`; context.font = `${size}pt DominionTitle`;

View File

@ -48,7 +48,7 @@ export const sampleCards: DominionCard[] = [
{ {
orientation: "card", orientation: "card",
title: "VP Card", title: "VP Card",
description: "+1 #\n\n-\n\n2 %", description: "+1#\n\n\n-\n\n\n2%",
types: [TYPE_VICTORY], types: [TYPE_VICTORY],
image: "", image: "",
artist: "", artist: "",