import { measureDominionText, parse, renderDominionText, } from "./dominiontext.ts"; import { DominionCardType, DominionColor, TYPE_ACTION } from "./types.ts"; import { DominionCard } from "./types.ts"; const imageCache: Record = {}; export const loadImage = ( key: string, src: string ): Promise => { return new Promise((resolve) => { if (key in imageCache && imageCache[key]) { resolve(imageCache[key]); } const img = new Image(); img.onload = () => { imageCache[key] = img; resolve(img); }; img.onerror = (e) => { console.log("err", e); }; img.src = src; }); }; const imageList = [ { key: "card-color-1", src: "/static/assets/CardColorOne.png", }, { key: "card-brown", src: "/static/assets/CardBrown.png", }, { key: "card-gray", src: "/static/assets/CardGray.png", }, { key: "card-description-focus", src: "/static/assets/DescriptionFocus.png", }, { key: "coin", src: "/static/assets/Coin.png", }, ]; export const loadImages = async () => { for (const imageInfo of imageList) { const { key, src } = imageInfo; await loadImage(key, src); } }; export const getImage = (key: string) => { const image = imageCache[key]; if (!image) { throw Error(`Tried to get an invalid image ${key}`); } return image; }; export const colorImage = ( image: HTMLImageElement, color?: string ): HTMLCanvasElement => { const canvas = document.createElement("canvas"); canvas.width = image.width; canvas.height = image.height; const context = canvas.getContext("2d")!; context.save(); context.drawImage(image, 0, 0); context.globalCompositeOperation = "multiply"; context.fillStyle = color ?? "white"; context.fillRect(0, 0, canvas.width, canvas.height); context.globalCompositeOperation = "destination-atop"; // restore transparency context.drawImage(image, 0, 0); context.restore(); return canvas; }; export const drawCard = ( context: CanvasRenderingContext2D, card: DominionCard ): Promise => { if (card.orientation === "card") { return drawStandardCard(context, card); } else { return drawLandscapeCard(context, card); } }; const getColors = (types: DominionCardType[]): { primary: string } => { const byPriority = [...types] .filter((type) => type.color) .sort((a, b) => b.color!.priority - a.color!.priority); if (byPriority.length === 0) { return { primary: "white" }; } const priority = byPriority[0]!; if (priority !== TYPE_ACTION) { return { primary: priority.color!.value }; } else { const overriders = byPriority.filter((t) => t.color!.overridesAction); if (overriders.length) { return { primary: overriders[0]!.color!.value }; } else { return { primary: priority.color!.value }; } } }; const drawStandardCard = async ( context: CanvasRenderingContext2D, card: DominionCard & { orientation: "card" } ): Promise => { const w = context.canvas.width; const h = context.canvas.height; context.save(); // Draw the image // Draw the card base const color = getColors(card.types).primary; // "#ffbc55"; context.drawImage(colorImage(getImage("card-color-1"), color), 0, 0); context.drawImage(getImage("card-gray"), 0, 0); context.drawImage(colorImage(getImage("card-brown"), "#ff9911"), 0, 0); context.drawImage(getImage("card-description-focus"), 44, 1094); // Draw the name context.font = "78pt DominionTitle"; await renderDominionText(context, parse(card.title), w / 2, 220, 1100); // Draw the description context.font = "60pt DominionText"; await renderDominionText( context, parse(card.description), w / 2, 1520, 1100 ); // Draw the types let size = 65; context.font = `${size}pt DominionTitle`; while ( ( await measureDominionText( context, parse(card.types.map((t) => t.name).join(" - ")) ) ).width > 800 ) { size -= 1; context.font = `${size}pt DominionTitle`; } await renderDominionText( context, parse(card.types.map((t) => t.name).join(" - ")), w / 2, 1930, 800 ); // Draw the cost context.font = "90pt DominionText"; await renderDominionText(context, parse(card.cost), 210, 1940, 200); // Draw the preview if (card.preview) { context.font = "90pt DominionText"; await renderDominionText(context, parse(card.preview), 200, 210, 200); await renderDominionText( context, parse(card.preview), w - 200, 210, 200 ); } // Draw the icon // Draw the credit context.restore(); }; const drawLandscapeCard = async ( context: CanvasRenderingContext2D, card: DominionCard & { orientation: "landscape" } ): Promise => { // TODO: everything };