more work

This commit is contained in:
Dylan Pizzo 2025-01-06 22:13:53 -05:00
parent 4e79fd38a1
commit 0099624165
5 changed files with 96 additions and 15 deletions

View File

@ -1,4 +1,5 @@
import { getImage } from "./draw.ts";
import { parseFont, stringifyFont } from "./fonthelper.ts";
export type Piece =
| { type: "text"; text: string; isBold?: boolean; isItalic?: boolean }
@ -18,6 +19,7 @@ type PieceMeasure = {
type Line = {
pieces: {
piece: Piece;
measure: PieceMeasure;
xOffset: number;
}[];
width: number;
@ -108,10 +110,12 @@ const breakPiece = pieceDef({
const coinPiece = pieceDef({
type: "coin",
measure(context, _piece) {
context.save();
const metrics = context.measureText(" ");
const height =
metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
const coinImage = getImage("coin");
context.restore();
return {
type: "content",
width: coinImage.width * (height / coinImage.height),
@ -131,6 +135,12 @@ const coinPiece = pieceDef({
measure.width,
height
);
const fontInfo = parseFont(context.font);
fontInfo.family = ["DominionSpecial"];
fontInfo.weight = "bold";
fontInfo.size = parseInt(fontInfo.size.toString()) * 1.2;
const font = stringifyFont(fontInfo);
context.font = font;
context.fillStyle = "black";
context.textAlign = "center";
context.fillText(piece.text, x + measure.width / 2, y);
@ -140,7 +150,7 @@ const coinPiece = pieceDef({
const pieceDefs = [textPiece, spacePiece, breakPiece, coinPiece];
let tools: PieceTools = {} as any;
const tools: PieceTools = {} as any;
const measurePiece = (context: CanvasRenderingContext2D, piece: Piece) => {
const def = pieceDefs.find((def) => def.type === piece.type)!;
@ -188,7 +198,7 @@ export const measureDominionText = async (
for (const pieceInfo of data) {
const line = lines[lines.length - 1]!;
if (pieceInfo.measure.type === "break") {
line.pieces.push({ piece: pieceInfo.piece, xOffset: line.width });
line.pieces.push({ ...pieceInfo, xOffset: line.width });
line.width += pieceInfo.measure.width;
line.ascent = Math.max(line.ascent, pieceInfo.measure.ascent);
line.descent = Math.max(line.descent, pieceInfo.measure.descent);
@ -196,14 +206,14 @@ export const measureDominionText = async (
} else {
if (line.width + pieceInfo.measure.width > maxWidth) {
lines.push({
pieces: [{ piece: pieceInfo.piece, xOffset: 0 }],
pieces: [{ ...pieceInfo, xOffset: 0 }],
width: pieceInfo.measure.width,
ascent: pieceInfo.measure.ascent,
descent: pieceInfo.measure.descent,
});
} else {
line.pieces.push({
piece: pieceInfo.piece,
...pieceInfo,
xOffset: line.width,
});
line.width += pieceInfo.measure.width;
@ -216,7 +226,15 @@ export const measureDominionText = async (
}
}
return {
lines,
lines: lines.map((line) => {
while (
line.pieces[line.pieces.length - 1] &&
line.pieces[line.pieces.length - 1]!.measure.type === "space"
) {
line.pieces = line.pieces.slice(0, -1);
}
return line;
}),
width: Math.max(...lines.map((line) => line.width)),
height: lines
.map((line) => line.ascent + line.descent)
@ -224,6 +242,8 @@ export const measureDominionText = async (
};
};
const debug = false;
export const renderDominionText = async (
context: CanvasRenderingContext2D,
pieces: Piece[],
@ -246,6 +266,30 @@ export const renderDominionText = async (
x - line.width / 2 + xOffset,
y - height / 2 + yOffset
);
if (debug) {
context.save();
context.strokeStyle = "blue";
context.lineWidth = 5;
const pieceMeasure = await measurePiece(context, piece);
context.strokeRect(
x - line.width / 2 + xOffset,
y - height / 2 - line.ascent + yOffset,
pieceMeasure.width,
pieceMeasure.ascent + pieceMeasure.descent
);
context.strokeStyle = "red";
context.beginPath();
context.moveTo(
x - line.width / 2 + xOffset - 5,
y - height / 2 + yOffset
);
context.lineTo(
x - line.width / 2 + xOffset + 5,
y - height / 2 + yOffset
);
context.stroke();
context.restore();
}
}
yOffset += line.descent;
}

View File

@ -107,24 +107,20 @@ const drawStandardCard = async (
context.drawImage(getImage("card-description-focus"), 44, 1094);
// Draw the name
context.font = "75pt DominionTitle";
await renderDominionText(
context,
parse("Moonlit Scheme"),
w / 2,
220,
1100
);
await renderDominionText(context, parse(card.title), w / 2, 220, 1100);
// Draw the description
context.font = "60pt DominionText";
await renderDominionText(
context,
parse("You may play an Action card from your hand costing up to $4."),
parse(card.description),
w / 2,
1520,
1100
);
// Draw the types
// Draw the cost
context.font = "90pt DominionText";
await renderDominionText(context, parse(card.price), 210, 1940, 200);
// Draw the preview
// Draw the icon
// Draw the credit

41
src/fonthelper.ts Normal file
View File

@ -0,0 +1,41 @@
import font from "npm:css-font";
export type FontInfo = {
style: "normal" | "italic" | "oblique";
variant: "normal" | "small-caps";
weight:
| "normal"
| "bold"
| "lighter"
| "bolder"
| "100"
| "200"
| "300"
| "400"
| "500"
| "600"
| "700"
| "800"
| "900";
stretch:
| "normal"
| "condensed"
| "semi-condensed"
| "extra-condensed"
| "ultra-condensed"
| "expanded"
| "semi-expanded"
| "extra-expanded"
| "ultra-expanded";
lineHeight: "normal" | number | string;
size: number | string;
family: string[];
};
export const parseFont = (fontString: string): FontInfo => {
return { ...font.parse(fontString) };
};
export const stringifyFont = (fontInfo: FontInfo): string => {
return font.stringify(fontInfo);
};

View File

@ -9,6 +9,6 @@ export const sampleCard: DominionCard = {
artist: "",
author: "",
version: "",
price: "",
price: "$",
preview: "",
};

View File

@ -17,7 +17,7 @@
}
@font-face {
font-family: 'DominionSpecials';
font-family: 'DominionSpecial';
font-display: auto;
src: local("Minion Std Black"), local("MinionStd-Black"), local("Minion Std"), local('Minion Pro'),
url('https://fonts.cdnfonts.com/s/13260/MinionPro-Regular.woff') format('woff'),