From 1846c067d214d6c64eaa1e0a16c2c851556958db Mon Sep 17 00:00:00 2001 From: Aaron Dalton Date: Thu, 9 Jan 2025 13:39:58 -0700 Subject: [PATCH] Allow pattern flood markers --- src/renderers/_base.ts | 60 ++++++++++++++++++++++++++++------------- src/schemas/schema.d.ts | 20 +++++++++++--- src/schemas/schema.json | 10 +++++-- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/renderers/_base.ts b/src/renderers/_base.ts index dca9b97..aed6435 100644 --- a/src/renderers/_base.ts +++ b/src/renderers/_base.ts @@ -437,46 +437,56 @@ export abstract class RendererBase { * @param name - The unique name of the pattern * @param canvas - The container into which to add the pattern */ - protected loadPattern(name: string, canvas?: Svg): void { + protected loadPattern(name: string, opts: {canvas?: Svg, fg?: string, bg?: string} = {}): void { + let canvas: Svg|undefined = this.rootSvg; + if (opts.canvas !== undefined) { + canvas = opts.canvas; + } if (canvas === undefined) { - if (this.rootSvg === undefined) { - throw new Error("Object in an invalid state!"); - } - canvas = this.rootSvg; + throw new Error("Object in an invalid state."); + } + + let fg = this.options.colourContext.strokes; + if (opts.fg !== undefined) { + fg = opts.fg; } + let bg = this.options.colourContext.background; + if (opts.bg !== undefined) { + bg = opts.bg; + } + // Keep in alphabetical order. // If you change any `id`s, you need to change them in the constructor, too. - switch (name) { case "chevrons": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "cross": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "dots": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "honeycomb": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "houndstooth": - canvas.defs().svg("houndstooth"); + canvas.defs().svg(`houndstooth`); break; case "microbial": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "slant": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "starsWhite": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "triangles": - canvas.defs().svg(""); + canvas.defs().svg(``); break; case "wavy": - canvas.defs().svg(""); + canvas.defs().svg(``); break; default: throw new Error(`The pattern name you requested (${name}) is not known.`); @@ -6699,15 +6709,29 @@ export abstract class RendererBase { if (typeof marker.colour === "object") { isGradient = true; } - colour = this.resolveColour(marker.colour ); + colour = this.resolveColour(marker.colour); } let opacity = 0.25; if ( ("opacity" in marker) && (marker.opacity !== undefined) ) { opacity = marker.opacity; } - let fill: FillData|SVGGradient; + let pattern: string | undefined; + if ( ("pattern" in marker) && (marker.pattern !== undefined) && (marker.pattern.length > 0) ) { + pattern = marker.pattern; + } + if (pattern !== undefined) { + this.loadPattern(pattern, {bg: "none", fg: typeof colour === "string" ? colour : undefined}); + } + let fill: FillData|SVGGradient|SVGElement; if (isGradient) { fill = colour as SVGGradient; + } else if (pattern !== undefined) { + if (pattern !== undefined) { + fill = this.rootSvg.findOne(`#${pattern}`) as SVGElement; + if (fill === undefined) { + throw new Error("Could not load the requested pattern."); + } + } } else { fill = {color: colour as string, opacity}; } diff --git a/src/schemas/schema.d.ts b/src/schemas/schema.d.ts index f86e0e5..f03eca0 100644 --- a/src/schemas/schema.d.ts +++ b/src/schemas/schema.d.ts @@ -69,6 +69,20 @@ export type BoardStyles = | "heightmap-squares" | "dvgc" | "dvgc-checkered"; +/** + * The patterns known by the renderer + */ +export type PatternName = + | "microbial" + | "chevrons" + | "honeycomb" + | "triangles" + | "wavy" + | "slant" + | "dots" + | "starsWhite" + | "cross" + | "houndstooth"; /** * The required schema for the `homeworlds` renderer. It supports 4 players and colours. The `board` property describes the systems. The `pieces` property describes the pieces. */ @@ -471,10 +485,7 @@ export interface BoardBasic { * The width of the zone expressed as a percentage of the cell size. If zero, the zone is omitted. */ width: number; - /** - * The name of one of the built-in patterns for fill. - */ - pattern?: string; + pattern?: PatternName; /** * Choose which of the four sides you want displayed. By default, it's all four. */ @@ -577,6 +588,7 @@ export interface MarkerFlood { * The colour of the shaded area. Can be either a number (which will be interpreted as a built-in player colour) or a hexadecimal colour string. */ colour?: PositiveInteger | Colourfuncs | Colourstrings | Gradient; + pattern?: PatternName; /** * 1 is fully opaque. 0 is fully transparent. */ diff --git a/src/schemas/schema.json b/src/schemas/schema.json index 91b8ee9..fed8f65 100644 --- a/src/schemas/schema.json +++ b/src/schemas/schema.json @@ -17,6 +17,10 @@ "type": "string", "pattern": "^1*2*3*$" }, + "patternName": { + "description": "The patterns known by the renderer", + "enum": ["microbial", "chevrons", "honeycomb", "triangles", "wavy", "slant", "dots", "starsWhite", "cross", "houndstooth"] + }, "colourstrings": { "description": "Pattern for hex colour strings", "anyOf": [ @@ -1200,6 +1204,9 @@ ], "default": "#000" }, + "pattern": { + "$ref": "#/$defs/patternName" + }, "opacity": { "description": "1 is fully opaque. 0 is fully transparent.", "type": "number", @@ -1973,8 +1980,7 @@ "maximum": 0.9 }, "pattern": { - "description": "The name of one of the built-in patterns for fill.", - "type": "string" + "$ref": "#/$defs/patternName" }, "show": { "description": "Choose which of the four sides you want displayed. By default, it's all four.",