more work
This commit is contained in:
		| @@ -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: "", | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user