more work
This commit is contained in:
parent
4e79fd38a1
commit
0099624165
@ -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;
|
||||
}
|
||||
|
12
src/draw.ts
12
src/draw.ts
@ -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
41
src/fonthelper.ts
Normal 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);
|
||||
};
|
@ -9,6 +9,6 @@ export const sampleCard: DominionCard = {
|
||||
artist: "",
|
||||
author: "",
|
||||
version: "",
|
||||
price: "",
|
||||
price: "$",
|
||||
preview: "",
|
||||
};
|
||||
|
@ -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'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user