more work
This commit is contained in:
parent
4e79fd38a1
commit
0099624165
@ -1,4 +1,5 @@
|
|||||||
import { getImage } from "./draw.ts";
|
import { getImage } from "./draw.ts";
|
||||||
|
import { parseFont, stringifyFont } from "./fonthelper.ts";
|
||||||
|
|
||||||
export type Piece =
|
export type Piece =
|
||||||
| { type: "text"; text: string; isBold?: boolean; isItalic?: boolean }
|
| { type: "text"; text: string; isBold?: boolean; isItalic?: boolean }
|
||||||
@ -18,6 +19,7 @@ type PieceMeasure = {
|
|||||||
type Line = {
|
type Line = {
|
||||||
pieces: {
|
pieces: {
|
||||||
piece: Piece;
|
piece: Piece;
|
||||||
|
measure: PieceMeasure;
|
||||||
xOffset: number;
|
xOffset: number;
|
||||||
}[];
|
}[];
|
||||||
width: number;
|
width: number;
|
||||||
@ -108,10 +110,12 @@ const breakPiece = pieceDef({
|
|||||||
const coinPiece = pieceDef({
|
const coinPiece = pieceDef({
|
||||||
type: "coin",
|
type: "coin",
|
||||||
measure(context, _piece) {
|
measure(context, _piece) {
|
||||||
|
context.save();
|
||||||
const metrics = context.measureText(" ");
|
const metrics = context.measureText(" ");
|
||||||
const height =
|
const height =
|
||||||
metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
|
metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
|
||||||
const coinImage = getImage("coin");
|
const coinImage = getImage("coin");
|
||||||
|
context.restore();
|
||||||
return {
|
return {
|
||||||
type: "content",
|
type: "content",
|
||||||
width: coinImage.width * (height / coinImage.height),
|
width: coinImage.width * (height / coinImage.height),
|
||||||
@ -131,6 +135,12 @@ const coinPiece = pieceDef({
|
|||||||
measure.width,
|
measure.width,
|
||||||
height
|
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.fillStyle = "black";
|
||||||
context.textAlign = "center";
|
context.textAlign = "center";
|
||||||
context.fillText(piece.text, x + measure.width / 2, y);
|
context.fillText(piece.text, x + measure.width / 2, y);
|
||||||
@ -140,7 +150,7 @@ const coinPiece = pieceDef({
|
|||||||
|
|
||||||
const pieceDefs = [textPiece, spacePiece, breakPiece, coinPiece];
|
const pieceDefs = [textPiece, spacePiece, breakPiece, coinPiece];
|
||||||
|
|
||||||
let tools: PieceTools = {} as any;
|
const tools: PieceTools = {} as any;
|
||||||
|
|
||||||
const measurePiece = (context: CanvasRenderingContext2D, piece: Piece) => {
|
const measurePiece = (context: CanvasRenderingContext2D, piece: Piece) => {
|
||||||
const def = pieceDefs.find((def) => def.type === piece.type)!;
|
const def = pieceDefs.find((def) => def.type === piece.type)!;
|
||||||
@ -188,7 +198,7 @@ export const measureDominionText = async (
|
|||||||
for (const pieceInfo of data) {
|
for (const pieceInfo of data) {
|
||||||
const line = lines[lines.length - 1]!;
|
const line = lines[lines.length - 1]!;
|
||||||
if (pieceInfo.measure.type === "break") {
|
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.width += pieceInfo.measure.width;
|
||||||
line.ascent = Math.max(line.ascent, pieceInfo.measure.ascent);
|
line.ascent = Math.max(line.ascent, pieceInfo.measure.ascent);
|
||||||
line.descent = Math.max(line.descent, pieceInfo.measure.descent);
|
line.descent = Math.max(line.descent, pieceInfo.measure.descent);
|
||||||
@ -196,14 +206,14 @@ export const measureDominionText = async (
|
|||||||
} else {
|
} else {
|
||||||
if (line.width + pieceInfo.measure.width > maxWidth) {
|
if (line.width + pieceInfo.measure.width > maxWidth) {
|
||||||
lines.push({
|
lines.push({
|
||||||
pieces: [{ piece: pieceInfo.piece, xOffset: 0 }],
|
pieces: [{ ...pieceInfo, xOffset: 0 }],
|
||||||
width: pieceInfo.measure.width,
|
width: pieceInfo.measure.width,
|
||||||
ascent: pieceInfo.measure.ascent,
|
ascent: pieceInfo.measure.ascent,
|
||||||
descent: pieceInfo.measure.descent,
|
descent: pieceInfo.measure.descent,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
line.pieces.push({
|
line.pieces.push({
|
||||||
piece: pieceInfo.piece,
|
...pieceInfo,
|
||||||
xOffset: line.width,
|
xOffset: line.width,
|
||||||
});
|
});
|
||||||
line.width += pieceInfo.measure.width;
|
line.width += pieceInfo.measure.width;
|
||||||
@ -216,7 +226,15 @@ export const measureDominionText = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
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)),
|
width: Math.max(...lines.map((line) => line.width)),
|
||||||
height: lines
|
height: lines
|
||||||
.map((line) => line.ascent + line.descent)
|
.map((line) => line.ascent + line.descent)
|
||||||
@ -224,6 +242,8 @@ export const measureDominionText = async (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const debug = false;
|
||||||
|
|
||||||
export const renderDominionText = async (
|
export const renderDominionText = async (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
pieces: Piece[],
|
pieces: Piece[],
|
||||||
@ -246,6 +266,30 @@ export const renderDominionText = async (
|
|||||||
x - line.width / 2 + xOffset,
|
x - line.width / 2 + xOffset,
|
||||||
y - height / 2 + yOffset
|
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;
|
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);
|
context.drawImage(getImage("card-description-focus"), 44, 1094);
|
||||||
// Draw the name
|
// Draw the name
|
||||||
context.font = "75pt DominionTitle";
|
context.font = "75pt DominionTitle";
|
||||||
await renderDominionText(
|
await renderDominionText(context, parse(card.title), w / 2, 220, 1100);
|
||||||
context,
|
|
||||||
parse("Moonlit Scheme"),
|
|
||||||
w / 2,
|
|
||||||
220,
|
|
||||||
1100
|
|
||||||
);
|
|
||||||
// Draw the description
|
// Draw the description
|
||||||
context.font = "60pt DominionText";
|
context.font = "60pt DominionText";
|
||||||
await renderDominionText(
|
await renderDominionText(
|
||||||
context,
|
context,
|
||||||
parse("You may play an Action card from your hand costing up to $4."),
|
parse(card.description),
|
||||||
w / 2,
|
w / 2,
|
||||||
1520,
|
1520,
|
||||||
1100
|
1100
|
||||||
);
|
);
|
||||||
// Draw the types
|
// Draw the types
|
||||||
// Draw the cost
|
// Draw the cost
|
||||||
|
context.font = "90pt DominionText";
|
||||||
|
await renderDominionText(context, parse(card.price), 210, 1940, 200);
|
||||||
// Draw the preview
|
// Draw the preview
|
||||||
// Draw the icon
|
// Draw the icon
|
||||||
// Draw the credit
|
// 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: "",
|
artist: "",
|
||||||
author: "",
|
author: "",
|
||||||
version: "",
|
version: "",
|
||||||
price: "",
|
price: "$",
|
||||||
preview: "",
|
preview: "",
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'DominionSpecials';
|
font-family: 'DominionSpecial';
|
||||||
font-display: auto;
|
font-display: auto;
|
||||||
src: local("Minion Std Black"), local("MinionStd-Black"), local("Minion Std"), local('Minion Pro'),
|
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'),
|
url('https://fonts.cdnfonts.com/s/13260/MinionPro-Regular.woff') format('woff'),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user