Allow big symbols
This commit is contained in:
		| @@ -9,6 +9,8 @@ export type Piece = | ||||
| 	| { | ||||
| 			type: "symbol"; | ||||
| 			symbol: "coin" | "debt" | "potion" | "vp" | "vp-token"; | ||||
| 			isBig?: boolean; | ||||
| 			prefix?: string; | ||||
| 			text: string; | ||||
| 			textColor: string; | ||||
| 	  }; | ||||
| @@ -157,13 +159,21 @@ const symbolPiece = pieceDef({ | ||||
| 		const metrics = context.measureText(" "); | ||||
| 		const height = | ||||
| 			metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; | ||||
| 		const prefixMetrics = context.measureText(piece.prefix ?? ""); | ||||
| 		const coinImage = getImage(piece.symbol); | ||||
| 		context.restore(); | ||||
| 		const { isBig } = piece; | ||||
| 		const scale = isBig ? 2.5 : 1; | ||||
| 		return { | ||||
| 			type: "content", | ||||
| 			width: coinImage.width * (height / coinImage.height), | ||||
| 			ascent: metrics.fontBoundingBoxAscent, | ||||
| 			descent: metrics.fontBoundingBoxDescent, | ||||
| 			width: | ||||
| 				scale * | ||||
| 				(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) { | ||||
| @@ -173,20 +183,34 @@ const symbolPiece = pieceDef({ | ||||
| 		// context.fillRect(x, y - measure.ascent, measure.width, height); | ||||
| 		context.drawImage( | ||||
| 			getImage(piece.symbol), | ||||
| 			x, | ||||
| 			x + measure.prefixWidth, | ||||
| 			y - measure.ascent, | ||||
| 			measure.width, | ||||
| 			measure.width - measure.prefixWidth, | ||||
| 			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); | ||||
| 		fontInfo.family = ["DominionSpecial"]; | ||||
| 		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); | ||||
| 		context.font = font; | ||||
| 		context.fillStyle = piece.textColor; | ||||
| 		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(); | ||||
| 	}, | ||||
| }); | ||||
| @@ -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 symbolMap = { | ||||
| 		"$": { symbol: "coin", textColor: "black" }, | ||||
| @@ -351,23 +379,28 @@ export const parse = (text: string): Piece[] => { | ||||
| 		"#": { symbol: "vp-token", textColor: "black" }, | ||||
| 	} as const; | ||||
| 	for (let i = 0; i < text.length; i++) { | ||||
| 		const char = text[i]; | ||||
| 		const char = text[i]!; | ||||
| 		if (char === " ") { | ||||
| 			pieces.push({ type: "space" }); | ||||
| 		} else if (char === "\n") { | ||||
| 			pieces.push({ type: "break" }); | ||||
| 		} else if (char && char in symbolMap) { | ||||
| 		} else if (char in symbolMap) { | ||||
| 			const c = char as keyof typeof symbolMap; | ||||
| 			const end = text.slice(i).match(new RegExp(`\\${c}\\w*`))![0] | ||||
| 				.length; | ||||
| 			const isBig = | ||||
| 				isDescription && | ||||
| 				["\n", undefined].includes(text[i - 1]) && | ||||
| 				["\n", undefined].includes(text[i + end]); | ||||
| 			pieces.push({ | ||||
| 				type: "symbol", | ||||
| 				...symbolMap[c], | ||||
| 				text: text.slice(i + 1, i + end), | ||||
| 				isBig, | ||||
| 			}); | ||||
| 			i += end - 1; | ||||
| 		} else if (char === "+") { | ||||
| 			const match = text.slice(i).match(/\+\d* \w+/); | ||||
| 			const match = text.slice(i).match(/\+\d*( \w+)?/); | ||||
| 			if (match) { | ||||
| 				const end = match[0].length; | ||||
| 				pieces.push({ | ||||
| @@ -389,8 +422,42 @@ export const parse = (text: string): Piece[] => { | ||||
| 			text[i + 1] === "\n" | ||||
| 		) { | ||||
| 			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 { | ||||
| 			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) }); | ||||
| 			i += end - 1; | ||||
| 		} | ||||
|   | ||||
| @@ -181,11 +181,12 @@ const drawStandardCard = async ( | ||||
| 	context.font = "60pt DominionText"; | ||||
| 	await renderDominionText( | ||||
| 		context, | ||||
| 		parse(card.description), | ||||
| 		parse(card.description, { isDescription: true }), | ||||
| 		w / 2, | ||||
| 		1490, | ||||
| 		1000 | ||||
| 	); | ||||
| 	console.log(card.title, parse(card.description)); | ||||
| 	// Draw the types | ||||
| 	size = 65; | ||||
| 	context.font = `${size}pt DominionTitle`; | ||||
|   | ||||
| @@ -48,7 +48,7 @@ export const sampleCards: DominionCard[] = [ | ||||
| 	{ | ||||
| 		orientation: "card", | ||||
| 		title: "VP Card", | ||||
| 		description: "+1 #\n\n-\n\n2 %", | ||||
| 		description: "+1#\n\n\n-\n\n\n2%", | ||||
| 		types: [TYPE_VICTORY], | ||||
| 		image: "", | ||||
| 		artist: "", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user