Skip to content

Commit 9a232a7

Browse files
committed
Merge branch 'develop'
2 parents dbc16d7 + 1846c06 commit 9a232a7

File tree

3 files changed

+66
-24
lines changed

3 files changed

+66
-24
lines changed

src/renderers/_base.ts

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -437,46 +437,56 @@ export abstract class RendererBase {
437437
* @param name - The unique name of the pattern
438438
* @param canvas - The container into which to add the pattern
439439
*/
440-
protected loadPattern(name: string, canvas?: Svg): void {
440+
protected loadPattern(name: string, opts: {canvas?: Svg, fg?: string, bg?: string} = {}): void {
441+
let canvas: Svg|undefined = this.rootSvg;
442+
if (opts.canvas !== undefined) {
443+
canvas = opts.canvas;
444+
}
441445
if (canvas === undefined) {
442-
if (this.rootSvg === undefined) {
443-
throw new Error("Object in an invalid state!");
444-
}
445-
canvas = this.rootSvg;
446+
throw new Error("Object in an invalid state.");
447+
}
448+
449+
let fg = this.options.colourContext.strokes;
450+
if (opts.fg !== undefined) {
451+
fg = opts.fg;
446452
}
453+
let bg = this.options.colourContext.background;
454+
if (opts.bg !== undefined) {
455+
bg = opts.bg;
456+
}
457+
447458
// Keep in alphabetical order.
448459
// If you change any `id`s, you need to change them in the constructor, too.
449-
450460
switch (name) {
451461
case "chevrons":
452-
canvas.defs().svg("<pattern id='chevrons' patternUnits='userSpaceOnUse' width='30' height='15' viewbox='0 0 60 30'><svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='60' height='30'><defs><rect id='_r' width='30' height='15' fill='#fff' stroke-width='2.5' stroke='#000'/><g id='_p'><use xlink:href='#_r'/><use y='15' xlink:href='#_r'/><use y='30' xlink:href='#_r'/><use y='45' xlink:href='#_r'/></g></defs><use xlink:href='#_p' transform='translate(0 -25) skewY(40)'/><use xlink:href='#_p' transform='translate(30 0) skewY(-40)'/></svg></pattern>");
462+
canvas.defs().svg(`<pattern id="chevrons" patternUnits="userSpaceOnUse" width="30" height="15" viewbox="0 0 60 30"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="60" height="30"><defs><rect id="_r" width="30" height="15" fill="${bg}" stroke-width="2.5" stroke="${fg}"/><g id="_p"><use xlink:href="#_r"/><use y="15" xlink:href="#_r"/><use y="30" xlink:href="#_r"/><use y="45" xlink:href="#_r"/></g></defs><use xlink:href="#_p" transform="translate(0 -25) skewY(40)"/><use xlink:href="#_p" transform="translate(30 0) skewY(-40)"/></svg></pattern>`);
453463
break;
454464
case "cross":
455-
canvas.defs().svg("<pattern id='cross' patternUnits='userSpaceOnUse' width='8' height='8'><svg xmlns='http://www.w3.org/2000/svg' width='8' height='8'><rect width='8' height='8' fill='#fff'/><path d='M0 0L8 8ZM8 0L0 8Z' stroke-width='0.5' stroke='#000'/></svg></pattern>");
465+
canvas.defs().svg(`<pattern id="cross" patternUnits="userSpaceOnUse" width="8" height="8"><svg xmlns="http://www.w3.org/2000/svg" width="8" height="8"><rect width="8" height="8" fill="${bg}"/><path d="M0 0L8 8ZM8 0L0 8Z" stroke-width="0.5" stroke="${fg}"/></svg></pattern>`);
456466
break;
457467
case "dots":
458-
canvas.defs().svg("<pattern id='dots' patternUnits='userSpaceOnUse' width='10' height='10'><svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><rect width='10' height='10' fill='#fff' /><circle cx='2.5' cy='2.5' r='2.5' fill='#000'/></svg></pattern>");
468+
canvas.defs().svg(`<pattern id="dots" patternUnits="userSpaceOnUse" width="10" height="10"><svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect width="10" height="10" fill="${bg}" /><circle cx="2.5" cy="2.5" r="2.5" fill="${fg}"/></svg></pattern>`);
459469
break;
460470
case "honeycomb":
461-
canvas.defs().svg("<pattern id='honeycomb' patternUnits='userSpaceOnUse' width='22.4' height='40' viewbox='0 0 56 100'><svg xmlns='http://www.w3.org/2000/svg' width='56' height='100'><rect width='56' height='100' fill='#fff'/><path d='M28 66L0 50L0 16L28 0L56 16L56 50L28 66L28 100' fill='none' stroke='#000' stroke-width='2'/><path d='M28 0L28 34L0 50L0 84L28 100L56 84L56 50L28 34' fill='none' stroke='#000' stroke-width='2'/></svg></pattern>");
471+
canvas.defs().svg(`<pattern id="honeycomb" patternUnits="userSpaceOnUse" width="22.4" height="40" viewbox="0 0 56 100"><svg xmlns="http://www.w3.org/2000/svg" width="56" height="100"><rect width="56" height="100" fill="${bg}"/><path d="M28 66L0 50L0 16L28 0L56 16L56 50L28 66L28 100" fill="none" stroke="${fg}" stroke-width="2"/><path d="M28 0L28 34L0 50L0 84L28 100L56 84L56 50L28 34" fill="none" stroke="${fg}" stroke-width="2"/></svg></pattern>`);
462472
break;
463473
case "houndstooth":
464-
canvas.defs().svg("<pattern id='houndstooth' patternUnits='userSpaceOnUse' width='24' height='24' viewbox='0 0 24 24'><svg width='24' height='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'><title>houndstooth</title><g fill='#000' fill-opacity='1' fill-rule='evenodd'><path d='M0 18h6l6-6v6h6l-6 6H0M24 18v6h-6M24 0l-6 6h-6l6-6M12 0v6L0 18v-6l6-6H0V0'/></g></svg></pattern>");
474+
canvas.defs().svg(`<pattern id="houndstooth" patternUnits="userSpaceOnUse" width="24" height="24" viewbox="0 0 24 24"><svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>houndstooth</title><g fill="${fg}" fill-opacity="1" fill-rule="evenodd"><path d="M0 18h6l6-6v6h6l-6 6H0M24 18v6h-6M24 0l-6 6h-6l6-6M12 0v6L0 18v-6l6-6H0V0"/></g></svg></pattern>`);
465475
break;
466476
case "microbial":
467-
canvas.defs().svg("<pattern id='microbial' patternUnits='userSpaceOnUse' width='20' height=20><svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><rect width='40' height='40' fill='#fff'/><circle r='9.2' stroke-width='1' stroke='#000' fill='none'/><circle cy='18.4' r='9.2' stroke-width='1px' stroke='#000' fill='none'/><circle cx='18.4' cy='18.4' r='9.2' stroke-width='1' stroke='#000' fill='none'/></svg></pattern>");
477+
canvas.defs().svg(`<pattern id="microbial" patternUnits="userSpaceOnUse" width="20" height=20><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><rect width="40" height="40" fill="${bg}"/><circle r="9.2" stroke-width="1" stroke="${fg}" fill="none"/><circle cy="18.4" r="9.2" stroke-width="1px" stroke="${fg}" fill="none"/><circle cx="18.4" cy="18.4" r="9.2" stroke-width="1" stroke="${fg}" fill="none"/></svg></pattern>`);
468478
break;
469479
case "slant":
470-
canvas.defs().svg("<pattern id='slant' patternUnits='userSpaceOnUse' width='10' height='10'><svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><rect width='10' height='10' fill='#fff'/><path d='M-1,1 l2,-2 M0,10 l10,-10 M9,11 l2,-2' stroke='#000' stroke-width='1'/></svg></pattern>");
480+
canvas.defs().svg(`<pattern id="slant" patternUnits="userSpaceOnUse" width="10" height="10"><svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect width="10" height="10" fill="${bg}"/><path d="M-1,1 l2,-2 M0,10 l10,-10 M9,11 l2,-2" stroke="${fg}" stroke-width="1"/></svg></pattern>`);
471481
break;
472482
case "starsWhite":
473-
canvas.defs().svg("<pattern id='starsWhite' patternUnits='userSpaceOnUse' width='40' height='40' viewbox='0 0 80 80'><svg xmlns='http://www.w3.org/2000/svg' width='80' height='80'><rect width='80' height='80' fill='#fff'/><circle cx='40' cy='40' r='40' fill='#000'/><path d='M0 40 A40 40 45 0 0 40 0 A40 40 315 0 0 80 40 A40 40 45 0 0 40 80 A40 40 270 0 0 0 40Z' fill='#fff'/></svg></pattern>");
483+
canvas.defs().svg(`<pattern id="starsWhite" patternUnits="userSpaceOnUse" width="40" height="40" viewbox="0 0 80 80"><svg xmlns="http://www.w3.org/2000/svg" width="80" height="80"><rect width="80" height="80" fill="${bg}"/><circle cx="40" cy="40" r="40" fill="${fg}"/><path d="M0 40 A40 40 45 0 0 40 0 A40 40 315 0 0 80 40 A40 40 45 0 0 40 80 A40 40 270 0 0 0 40Z" fill="${bg}"/></svg></pattern>`);
474484
break;
475485
case "triangles":
476-
canvas.defs().svg("<pattern id='triangles' patternUnits='userSpaceOnUse' width='15' height='15'><svg xmlns='http://www.w3.org/2000/svg' width='15' height='15'><rect width='15' height='15' fill='#fff'/><path d='M0 15L7.5 0L15 15Z' fill='#000'/></svg></pattern>");
486+
canvas.defs().svg(`<pattern id="triangles" patternUnits="userSpaceOnUse" width="15" height="15"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15"><rect width="15" height="15" fill="${bg}"/><path d="M0 15L7.5 0L15 15Z" fill="${fg}"/></svg></pattern>`);
477487
break;
478488
case "wavy":
479-
canvas.defs().svg("<pattern id='wavy' patternUnits='userSpaceOnUse' width='15' height='20' viewbox='0 0 75 100'><svg xmlns='http://www.w3.org/2000/svg' width='75' height='100'><rect width='75' height='100' fill='#fff'/><circle cx='75' cy='50' r='28.3%' stroke-width='12' stroke='#000' fill='none'/><circle cx='0' r='28.3%' stroke-width='12' stroke='#000' fill='none'/><circle cy='100' r='28.3%' stroke-width='12' stroke='#000' fill='none'/></svg></pattern>");
489+
canvas.defs().svg(`<pattern id="wavy" patternUnits="userSpaceOnUse" width="15" height="20" viewbox="0 0 75 100"><svg xmlns="http://www.w3.org/2000/svg" width="75" height="100"><rect width="75" height="100" fill="${bg}"/><circle cx="75" cy="50" r="28.3%" stroke-width="12" stroke="${fg}" fill="none"/><circle cx="0" r="28.3%" stroke-width="12" stroke="${fg}" fill="none"/><circle cy="100" r="28.3%" stroke-width="12" stroke="${fg}" fill="none"/></svg></pattern>`);
480490
break;
481491
default:
482492
throw new Error(`The pattern name you requested (${name}) is not known.`);
@@ -6699,15 +6709,29 @@ export abstract class RendererBase {
66996709
if (typeof marker.colour === "object") {
67006710
isGradient = true;
67016711
}
6702-
colour = this.resolveColour(marker.colour );
6712+
colour = this.resolveColour(marker.colour);
67036713
}
67046714
let opacity = 0.25;
67056715
if ( ("opacity" in marker) && (marker.opacity !== undefined) ) {
67066716
opacity = marker.opacity;
67076717
}
6708-
let fill: FillData|SVGGradient;
6718+
let pattern: string | undefined;
6719+
if ( ("pattern" in marker) && (marker.pattern !== undefined) && (marker.pattern.length > 0) ) {
6720+
pattern = marker.pattern;
6721+
}
6722+
if (pattern !== undefined) {
6723+
this.loadPattern(pattern, {bg: "none", fg: typeof colour === "string" ? colour : undefined});
6724+
}
6725+
let fill: FillData|SVGGradient|SVGElement;
67096726
if (isGradient) {
67106727
fill = colour as SVGGradient;
6728+
} else if (pattern !== undefined) {
6729+
if (pattern !== undefined) {
6730+
fill = this.rootSvg.findOne(`#${pattern}`) as SVGElement;
6731+
if (fill === undefined) {
6732+
throw new Error("Could not load the requested pattern.");
6733+
}
6734+
}
67116735
} else {
67126736
fill = {color: colour as string, opacity};
67136737
}

src/schemas/schema.d.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ export type BoardStyles =
6969
| "heightmap-squares"
7070
| "dvgc"
7171
| "dvgc-checkered";
72+
/**
73+
* The patterns known by the renderer
74+
*/
75+
export type PatternName =
76+
| "microbial"
77+
| "chevrons"
78+
| "honeycomb"
79+
| "triangles"
80+
| "wavy"
81+
| "slant"
82+
| "dots"
83+
| "starsWhite"
84+
| "cross"
85+
| "houndstooth";
7286
/**
7387
* 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.
7488
*/
@@ -471,10 +485,7 @@ export interface BoardBasic {
471485
* The width of the zone expressed as a percentage of the cell size. If zero, the zone is omitted.
472486
*/
473487
width: number;
474-
/**
475-
* The name of one of the built-in patterns for fill.
476-
*/
477-
pattern?: string;
488+
pattern?: PatternName;
478489
/**
479490
* Choose which of the four sides you want displayed. By default, it's all four.
480491
*/
@@ -577,6 +588,7 @@ export interface MarkerFlood {
577588
* 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.
578589
*/
579590
colour?: PositiveInteger | Colourfuncs | Colourstrings | Gradient;
591+
pattern?: PatternName;
580592
/**
581593
* 1 is fully opaque. 0 is fully transparent.
582594
*/

src/schemas/schema.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
"type": "string",
1818
"pattern": "^1*2*3*$"
1919
},
20+
"patternName": {
21+
"description": "The patterns known by the renderer",
22+
"enum": ["microbial", "chevrons", "honeycomb", "triangles", "wavy", "slant", "dots", "starsWhite", "cross", "houndstooth"]
23+
},
2024
"colourstrings": {
2125
"description": "Pattern for hex colour strings",
2226
"anyOf": [
@@ -1200,6 +1204,9 @@
12001204
],
12011205
"default": "#000"
12021206
},
1207+
"pattern": {
1208+
"$ref": "#/$defs/patternName"
1209+
},
12031210
"opacity": {
12041211
"description": "1 is fully opaque. 0 is fully transparent.",
12051212
"type": "number",
@@ -1973,8 +1980,7 @@
19731980
"maximum": 0.9
19741981
},
19751982
"pattern": {
1976-
"description": "The name of one of the built-in patterns for fill.",
1977-
"type": "string"
1983+
"$ref": "#/$defs/patternName"
19781984
},
19791985
"show": {
19801986
"description": "Choose which of the four sides you want displayed. By default, it's all four.",

0 commit comments

Comments
 (0)