@johnmorrisdotca/kyogijo-stadiums 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ All notable changes to this project are written here. The format follows
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.10.0] - 2026-10-14
11
+
12
+ ### Added
13
+
14
+ - **The demo has an optional Background menu.** None by default, then the family's twenty-five backgrounds (`scripts/family-backgrounds.ts`, version 1.0.0, copied byte for byte from taisen-brackets and pinned by version and sha256), also by `?background=<name>`. It draws one behind the stage in the dark or the light variant of the page's look, takes the stage's text colour from the ink the background returns, and loads the module only when one is chosen. It is presentation only: the drawing's SVG is the same string with and without it, and an e2e test holds that. The package ships none of it and still has no dependency.
15
+
16
+ ### Changed
17
+
18
+ - **Every README picture stands on one of the family's backgrounds,** in a light and a dark twin (ice behind the rinks, floodlights behind the football field, a royal purple behind the ballpark, a glow or a spotlight behind the courts), and `pnpm screenshots:readme` remakes all twenty in one run.
19
+ - **The docs' and the README's samples use real countries,** Canada, the USA and Japan first, with their names and colours and no flag (a snippet cannot await Hata); where a sample shows marks it draws a maple leaf and a sun disc of its own. The gallery's teams and the pool races' swimmers' countries are real too.
20
+
21
+ ## [0.9.0] - 2026-10-14
22
+
23
+ ### Added
24
+
25
+ - **Country flags from a plug-in: `useFlags(render)` and the `flags` option.** A team takes a country's code, `flag: "CA"`, and the flag is drawn by a function you plug in, as the emblems are by `useEmblems`. The renderer is `(code, { shape, size, theme }) => string` (an SVG document, or nothing for a code it has no flag for), synchronous because a drawing is a pure function of its options: it is the shape [Taisen Brackets](https://www.npmjs.com/package/@johnmorrisdotca/taisen-brackets) takes, so one adapter over [Hata](https://github.com/johnmorrisdotca/hata) serves both. `shape` is `round` (a round mark, a pageant's stage), `rect` (a plain mark, a banner, a badge, a pageant's carpet, in its own proportions) or `square`; `size` is a nominal width in pixels; `theme` is `light`, `dark` or `inherit`. `useFlags` is in the main entry and in `/element`; `flags: render` in the options of a drawing (or the `surface` of a chart) wins over it for that drawing. The same code works for `Swimmer.country` and `LineupPlayer.country` (where `flag` is missing), for the `country` of an athlete or a skater of a lane draw or a start list, a layer's mark of the shape `logo` for a team, and the element's `home-flag` and `away-flag` attributes. A team's `flag` wins over its `logo` where the renderer has a flag for the code; with no renderer, or none for the code, a drawing is the text it was (and a code that is not a code is never asked about). A round flag turns with its team's name as a round logo does. Kyogijo imports no flag and keeps no dependencies; `@johnmorrisdotca/hata` 1.5.0 is a development dependency (for the demo and the tests) and an optional peer one. [Flags](./docs/flags.md).
26
+
27
+ ### Changed
28
+
29
+ - **The demo's teams are real countries, drawn with Hata's flags.** The made-up teams (Harbour City Gulls and the rest) and the sixteen made-up nations of `demo/nations.js` are replaced by Canada, USA, Japan, Mexico, Australia, Brazil, England, Korea, Germany, France and Italy, each with its national flag through the plug-in (the build loads the flags it draws from Hata into the page), and the pool's swimmers, who still do not exist, swim for real countries. The demo's teams have a new "Flag" logo choice, the default; "Own logo" shows a logo of your own beside it: a maple leaf with the word CANADA, a red sun disc with the word JAPAN and, for the others, a roundel of their letters, all drawn in the demo's code. No federation's crest or logo, and no Olympic rings, is used. The embedded frame takes `aflag` and `hflag`. The made-up nations stay, for the tests only, in `src/nations.fixture.ts`, so that no drawing in a test changed.
30
+
10
31
  ## [0.8.0] - 2026-10-14
11
32
 
12
33
  ### Added
package/NOTICE.md CHANGED
@@ -45,6 +45,8 @@ picture or code of the sources is copied; each source is named here so that the
45
45
  | `parks`: the coordinates of each ballpark (`lat`, `lon`) and the years it opened and closed (`opened`, `closed`) | The item's coordinate location (P625), its date of official opening or inception (P1619, P571) and of official closure or dissolution (P3999, P576), read with the Wikidata API by `scripts/fetch-park-coordinates.mjs` and checked by `scripts/check-parks.mjs` (ES CON Field's opening, 2023, is read from its article) | Wikidata's data is CC0 (https://creativecommons.org/publicdomain/zero/1.0/) |
46
46
  | `events`: the special games, their days, venues, hosts and where a surface stood | The English Wikipedia articles of each game and of its venue, at the revision cited below, and three articles of the press (Sports Video Group, NHL.com, The Boston Globe), named below with their authors and dates; the size of a carrier from the Nimitz class's article | Facts, CC BY-SA 4.0 articles as above; no text copied |
47
47
  | The atlas (`@johnmorrisdotca/kyogijo-stadiums/atlas`): the places and their map | The parks, grounds and arenas above, joined; the demo's and docs/atlas.md's map is drawn by chizu (MIT) from Natural Earth, which is in the public domain (https://www.naturalearthdata.com/about/terms-of-use/) | Facts and CC0 data; Natural Earth is public domain; chizu is a development dependency and none of it is in the package |
48
+ | The demo's country flags | [Hata](https://github.com/johnmorrisdotca/hata) (`@johnmorrisdotca/hata`, a development dependency): the flags of the countries in `demo/nations.js`, loaded when the demo is built and written into the demo site with Hata's licence and notice (`site/hata/`); the package itself draws no flag | Hata is MIT; each flag's own source, author and licence are in Hata's NOTICE.md |
49
+ | tooling: the demo's backgrounds and the README's pictures | `scripts/family-backgrounds.ts`, version 1.0.0: the family's shared module, copied byte for byte from taisen-brackets. Twenty-five backgrounds drawn in code from gradients, patterns and paths, all by this package's author, none traced from a picture, a poster, a logo, a trophy or a photograph | MIT. The package ships none of it, and no surface is drawn on a background: the background is the page around it |
48
50
 
49
51
  ## The ballparks' articles
50
52
 
package/README.md CHANGED
@@ -20,14 +20,14 @@ The NFL, CFL and IFAF football fields, the NHL rink, the NBA court, the soccer p
20
20
  <td align="center" valign="top">
21
21
  <picture>
22
22
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/hero-desk-dark.webp">
23
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/hero-desk-light.webp" alt="The demo on a desk, in English: the heading Kyogijo Stadiums with the language chooser, the Docs and API reference links, five cloth patches and the Help switch, and an NHL rink drawn wide on green felt, with a made-up game on it, the Northern Owls and their owl emblem on the left, the Lakeshore Anchors and their anchor on the right, and a panel of the score 3 to 2, Final/OT, in the middle. The controls on the right list the sports, from the NFL and the NHL to handball, and then the layout and the teams." width="640">
23
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/hero-desk-light.webp" alt="The demo on a desk, in English: the heading Kyogijo Stadiums with the language chooser, the Docs and API reference links, five cloth patches and the Help switch, and an NHL rink drawn wide on an ice-blue background of faint skate marks and rink lines, with a made-up game on it, the USA and its flag on the left, Canada and its flag on the right, and a panel of the score 3 to 2, Final/OT, in the middle. The controls on the right list the sports, from the NFL and the NHL to handball, and then the layout and the teams." width="640">
24
24
  </picture>
25
25
  <br><em>The demo on a desk: a rink, with the teams on their sides and the score in the middle.</em>
26
26
  </td>
27
27
  <td align="center" valign="top">
28
28
  <picture>
29
29
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/hero-phone-dark.webp">
30
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/hero-phone-light.webp" alt="The demo on a phone: the heading Kyogijo Stadiums over the page's controls, and under them a football field turned a quarter to stand tall, the visiting team's blue end zone at the top and the home team's red end zone at the bottom, each with its logo and name written across it, the yard numbers upright, and a score panel at midfield reading 27 to 24, Final." width="240">
30
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/hero-phone-light.webp" alt="The demo on a phone: the heading Kyogijo Stadiums over the page's controls, and under them, on a background of floodlight beams, a football field turned a quarter to stand tall, Mexico's green end zone at the top and the USA's navy end zone at the bottom, each with its flag and name written across it, the yard numbers upright, and a score panel at midfield reading 27 to 24, Final." width="240">
31
31
  </picture>
32
32
  <br><em>On a phone the same surface stands tall, the words still upright.</em>
33
33
  </td>
@@ -47,12 +47,12 @@ import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";
47
47
 
48
48
  const svg = drawKyogijo({
49
49
  sport: "nhl",
50
- away: { name: "Northern Owls", abbr: "NOW", score: 3, color: "#3a2d6b" },
51
- home: { name: "Lakeshore Anchors", abbr: "LSA", score: 2, color: "#0f7a7a" },
50
+ away: { name: "USA", abbr: "USA", score: 3, color: "#1c3f7a" },
51
+ home: { name: "Canada", abbr: "CAN", score: 2, color: "#d52b1e" },
52
52
  status: "final-ot",
53
53
  competition: "Cup Final, Game 7",
54
54
  });
55
- console.log(svg.startsWith("<svg"), svg.includes("Northern Owls 3, Lakeshore Anchors 2"));
55
+ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
56
56
  // true true
57
57
  ```
58
58
 
@@ -60,7 +60,7 @@ console.log(svg.startsWith("<svg"), svg.includes("Northern Owls 3, Lakeshore Anc
60
60
 
61
61
  ```html
62
62
  <script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kyogijo-stadiums@0/dist/element-define.js"></script>
63
- <kyogijo-field sport="nhl" orientation="auto" away="Northern Owls" home="Lakeshore Anchors" away-score="3" home-score="2" status="final-ot"></kyogijo-field>
63
+ <kyogijo-field sport="nhl" orientation="auto" away="USA" home="Canada" away-score="3" home-score="2" status="final-ot"></kyogijo-field>
64
64
  ```
65
65
 
66
66
  ## Who it is for
@@ -94,6 +94,7 @@ console.log(svg.startsWith("<svg"), svg.includes("Northern Owls 3, Lakeshore Anc
94
94
  - **Lineups.** A `lineup` layer places a team's players by position code (`GK`, `CB`, `HK`, `C`) with no coordinates: it reads where each stands from a formation (36 of them, in 13 sports), draws a disc or a jersey with the shirt number and the name under it, a captain's C and a flag, and puts the visitors at the other end. A drawing with a lineup puts the score in the strip under it, so the panel hides no player. [Lineups](./docs/team-shape.md#lineups).
95
95
  - **A pageant.** Each team's flag or crest laid large over its half of the surface, as a stadium lays giant flags and crests for a final: `pageant: "carpet"` (a flag at its own ratio with a border and a gentle fabric) or `"stage"` (a crest on a round disc with a gold ring), an emblem or a trophy of your own in the centre circle, the score in the middle or in the strip, upright wide and tall, in light and dark, with an entrance in CSS for readers who have not asked for less motion. [The pageant](./docs/pageant.md).
96
96
  - **Trophies, medals, balls and crests, by id.** `useEmblems(renderEmblem)` plugs in the sister package [Dougu Sports 道具](https://johnmorrisdotca.github.io/dougu-sports/) in one line, and an id goes wherever a logo, a flag or a mark is taken: `logo: "crest:shield"` (a crest in the team's colour with its letters), `pageant: { emblem: "trophy:hockey-cup" }`, `"sport:nhl/line"`, `"ball:puck"`, `"cup"`. Kyogijo bundles no emblem and keeps zero dependencies; without the plug-in an id is refused like any unsafe address. [Emblems](./docs/emblems.md).
97
+ - **Country flags, by code.** `useFlags(render)` plugs in the sister package [Hata 旗](https://github.com/johnmorrisdotca/hata) through a small adapter, and a team's `flag: "CA"` is its flag: round in a round mark, at its own proportions on a banner, a badge or a pageant's carpet. The same adapter serves [Taisen Brackets](https://github.com/johnmorrisdotca/taisen-brackets). Kyogijo bundles no flag and keeps zero dependencies; without the plug-in a code is ignored. [Flags](./docs/flags.md).
97
98
  - **Zoom to a part of a surface.** `range: "offensive-zone"` crops a drawing to a rink's zone, a half court, the paint, the red zone, a soccer half, third or penalty area, the infield, a curling house, or a box of your own in any frame, with its data, heat, labels and score following. [Display ranges](./docs/ranges.md).
98
99
  - **Wide, tall or fit the box.** Every surface lies wide or tall: tall turns it a quarter, keeps every word upright and puts the teams top and bottom. With `orientation: "auto"` the browser helpers follow the box.
99
100
  - **Where a point lies, by the rules, and a click as a place.** `zoneAt("nhl", [69, 22], { frame: "nhl-api" })` names the zone and the area in it from the rink's, court's, pitch's, park's or field's own figures (the offensive zone and its face-off circle, the frontcourt and the corner three, the attacking third and the six-yard box, the infield and the warning track, the red zone and between the hashes), with `isThreePointer`, `inSlot`, `inPenaltyArea`, `isFair`, `overWall` and the like, and `isHomeRun(park, point, { height })` from the park's fence and wall; `clientPointToField(svg, x, y, { provider })` is a pointer's place in any of the frames, with the zone, and `fieldPointToClient` the way back. `marks: true` writes `data-mark-id`, `data-index` and `data-zone` on every mark of a layer, for one listener to link it to a table. [Zones](./docs/zones.md), [pointing](./docs/pointer.md).
@@ -165,8 +166,8 @@ import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";
165
166
 
166
167
  const svg = drawKyogijo({
167
168
  sport: "nhl",
168
- away: { name: "Northern Owls", abbr: "NOW", score: 3, color: "#3a2d6b" },
169
- home: { name: "Lakeshore Anchors", abbr: "LSA", score: 2, color: "#0f7a7a" },
169
+ away: { name: "USA", abbr: "USA", score: 3, color: "#1c3f7a" },
170
+ home: { name: "Canada", abbr: "CAN", score: 2, color: "#d52b1e" },
170
171
  status: "final-ot",
171
172
  competition: "Cup Final, Game 7",
172
173
  date: "June 24",
@@ -178,7 +179,7 @@ console.log(svg.includes("Cup Final, Game 7"), svg.includes("Final/OT"));
178
179
  <p align="center">
179
180
  <picture>
180
181
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/football-desk-dark.webp">
181
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/football-desk-light.webp" alt="A football field drawn wide on the demo's felt: the visiting team's blue end zone on the left with its gull emblem and its name written along it, the home team's rust-red end zone on the right with its bison, the yard lines, hash marks and upright and upside-down yard numbers between them, and the score panel at midfield reading 27 to 24, Final, Championship Game." width="720">
182
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/football-desk-light.webp" alt="A football field drawn wide on a background of floodlight beams: Mexico's green end zone on the left with its flag and its name written along it, the USA's navy end zone on the right with its flag, the yard lines, hash marks and upright and upside-down yard numbers between them, and the score panel at midfield reading 27 to 24, Final, Championship Game." width="720">
182
183
  </picture>
183
184
  <br><em>A football field: the end zones in the teams' colours, the score at midfield.</em>
184
185
  </p>
@@ -195,12 +196,12 @@ useEmblems(renderEmblem);
195
196
 
196
197
  const svg = drawKyogijo({
197
198
  sport: "soccer",
198
- away: { name: "Harbour City Gulls", abbr: "HCG", score: 2, color: "#1f5fa8", logo: "crest:shield" },
199
- home: { name: "Prairie Ridge Bison", abbr: "PRB", score: 1, color: "#b5452c", logo: "crest:roundel" },
199
+ away: { name: "Brazil", abbr: "BRA", score: 2, color: "#009739", logo: "crest:shield" },
200
+ home: { name: "England", abbr: "ENG", score: 1, color: "#c8102e", logo: "crest:roundel" },
200
201
  status: "final",
201
202
  pageant: { style: "stage", emblem: "trophy:soccer-globe", emblemName: "Northern Cup" },
202
203
  });
203
- console.log(svg.includes(encodeURIComponent(">HCG<")), svg.includes("Northern Cup"));
204
+ console.log(svg.includes(encodeURIComponent(">BRA<")), svg.includes("Northern Cup"));
204
205
  // true true
205
206
  ```
206
207
 
@@ -212,7 +213,7 @@ import { drawKyogijo, drawSurface } from "@johnmorrisdotca/kyogijo-stadiums";
212
213
  // No teams: just the NFL field at its true shape, 120 by 53⅓ yards with 12 feet of ground round it.
213
214
  console.log(/viewBox="-12 -12 384 184"/.test(drawSurface({ sport: "nfl" })));
214
215
  // true
215
- const game = { away: { name: "Harbour City Gulls", score: 27 }, home: { name: "Prairie Ridge Bison", score: 24 }, status: "final" };
216
+ const game = { away: { name: "Mexico", score: 27 }, home: { name: "USA", score: 24 }, status: "final" };
216
217
  const wide = drawKyogijo({ sport: "nfl", ...game, orientation: "landscape" });
217
218
  const tall = drawKyogijo({ sport: "nfl", ...game, orientation: "portrait" });
218
219
  const box = (svg: string) => /viewBox="[^ ]+ [^ ]+ ([^ ]+) ([^ "]+)"/.exec(svg)!.slice(1).map(Number);
@@ -223,7 +224,7 @@ console.log(box(wide), box(tall));
223
224
  <p align="center">
224
225
  <picture>
225
226
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/tall-phone-dark.webp">
226
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/tall-phone-light.webp" alt="A hockey rink standing tall on a phone, the same game as on the desk: the Northern Owls' emblem and name in the upper zone, the Lakeshore Anchors' in the lower, each reading upright, the score panel between them over the centre line." width="240">
227
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/tall-phone-light.webp" alt="A hockey rink standing tall on a phone, on an ice-blue background, the same game as on the desk: the USA's flag and name in the upper zone, Canada's in the lower, each reading upright, the score panel between them over the centre line." width="240">
227
228
  </picture>
228
229
  <br><em>The same game tall: the teams top and bottom, every word upright.</em>
229
230
  </p>
@@ -258,7 +259,7 @@ console.log(svg.includes("甲子園球場のグラウンド"), svg.includes("阪
258
259
  <p align="center">
259
260
  <picture>
260
261
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/ballpark-desk-dark.webp">
261
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/ballpark-desk-light.webp" alt="The baseball field of Hanshin Koshien Stadium with the outfield fence drawn through its published distances, 95 metres at the lines and 118 metres in the alleys and the middle, with mown arcs on the grass, the warning track, the infield dirt, and a red and a green panel in the foul ground at the bottom for the teams' dugouts." width="640">
262
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/ballpark-desk-light.webp" alt="The baseball field of Hanshin Koshien Stadium on a royal purple background, with the outfield fence drawn through its published distances, 95 metres at the lines and 118 metres in the alleys and the middle, with mown arcs on the grass, the warning track, the infield dirt, and a red and a navy panel in the foul ground at the bottom for the teams' dugouts, each with its country's flag, Japan's and the USA's." width="640">
262
263
  </picture>
263
264
  <br><em>A ballpark's fence, drawn through the distances its article publishes.</em>
264
265
  </p>
@@ -306,8 +307,8 @@ import { drawBadge } from "@johnmorrisdotca/kyogijo-stadiums";
306
307
 
307
308
  const badge = drawBadge({
308
309
  sport: "nba",
309
- away: { name: "Summit Peaks", abbr: "SMT", score: 98, color: "#14233f" },
310
- home: { name: "Metro Bolts", abbr: "MTB", score: 104, color: "#c2410c" },
310
+ away: { name: "Australia", abbr: "AUS", score: 98, color: "#00843d" },
311
+ home: { name: "Japan", abbr: "JPN", score: 104, color: "#bc002d" },
311
312
  status: "Q4 2:31",
312
313
  });
313
314
  console.log(/viewBox="0 0 440 64"/.test(badge));
@@ -317,7 +318,7 @@ console.log(/viewBox="0 0 440 64"/.test(badge));
317
318
  <p align="center">
318
319
  <picture>
319
320
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/badges-desk-dark.webp">
320
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/badges-desk-light.webp" alt="A list of eight score strips in the demo, each a team block with its emblem, a short name and its score at each end, in the team's colour, and in the middle a small picture of the sport and the state of the game, such as Final, Final/OT and 2nd period." width="640">
321
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/badges-desk-light.webp" alt="A list of eight score strips in the demo, on a midnight-blue background, each a team block with its country's flag, a short name and its score at each end, in the team's colour, and in the middle a small picture of the sport and the state of the game, such as Final, Final/OT and 2nd period." width="640">
321
322
  </picture>
322
323
  <br><em>Badges for a list of games.</em>
323
324
  </p>
@@ -338,7 +339,7 @@ console.log(svg.includes("--ky-key:#1e4f8f"), svg.includes("METRO BOLTS"));
338
339
  <p align="center">
339
340
  <picture>
340
341
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/court-desk-dark.webp">
341
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/court-desk-light.webp" alt="A basketball court in the two-tone look: a pale floor with a deep blue key, centre circle and border, the words SUMMIT PEAKS and METRO BOLTS along the baselines, each team's emblem and name on its half, and the score panel at centre court reading 108 to 112, Finals, Game 6." width="640">
342
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/court-desk-light.webp" alt="A basketball court in the two-tone look, in a warm glow: a pale floor with a deep blue key, centre circle and border, the words AUSTRALIA and JAPAN along the baselines, each country's flag and name on its half, and the score panel at centre court reading 108 to 112, Finals, Game 6." width="640">
342
343
  </picture>
343
344
  <br><em>A court in a look of its own: the paint, the border and the words on the baselines are options.</em>
344
345
  </p>
@@ -368,7 +369,7 @@ The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewp
368
369
  <p align="center">
369
370
  <picture>
370
371
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-volleyball-desk-dark.webp">
371
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-volleyball-desk-light.webp" alt="A volleyball court from behind an end line, turned in the demo: the net at 2.43 metres on its posts with the red and white antennae, and under it the buttons for the four viewpoints, turning, raising, zooming and resetting." width="640">
372
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-volleyball-desk-light.webp" alt="A volleyball court from behind an end line under a spotlight, turned in the demo: the net at 2.43 metres on its posts with the red and white antennae, and under it the buttons for the four viewpoints, turning, raising, zooming and resetting." width="640">
372
373
  </picture>
373
374
  <br><em>A volleyball net at its rulebook height, with its posts and antennae.</em>
374
375
  </p>
@@ -376,7 +377,7 @@ The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewp
376
377
  <p align="center">
377
378
  <picture>
378
379
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-rink-desk-dark.webp">
379
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-rink-desk-light.webp" alt="An ice rink from a low corner, turned in the demo: the boards with their glass round the ice, a goal at each end, and the score on the ice." width="640">
380
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-rink-desk-light.webp" alt="An ice rink from a low corner on an ice-blue background, turned in the demo: the boards with their glass round the ice, a goal at each end, and the score on the ice." width="640">
380
381
  </picture>
381
382
  <br><em>A rink with its boards, glass and goals.</em>
382
383
  </p>
@@ -384,7 +385,7 @@ The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewp
384
385
  <p align="center">
385
386
  <picture>
386
387
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-court-desk-dark.webp">
387
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-court-desk-light.webp" alt="A basketball court from the main camera, turned in the demo: a basket on its backboard and padded stanchion at each end of the floor." width="640">
388
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-court-desk-light.webp" alt="A basketball court from the main camera in a warm glow, turned in the demo: a basket on its backboard and padded stanchion at each end of the floor." width="640">
388
389
  </picture>
389
390
  <br><em>A court with a basket at each end, the rim at 10 feet.</em>
390
391
  </p>
@@ -396,8 +397,8 @@ import { drawKyogijo, soccerSpec } from "@johnmorrisdotca/kyogijo-stadiums";
396
397
 
397
398
  const svg = drawKyogijo({
398
399
  sport: "soccer",
399
- away: { name: "Northern Owls", abbr: "NOW", score: 2, penalties: 4, color: "#3a2d6b" },
400
- home: { name: "Lakeshore Anchors", abbr: "LSA", score: 2, penalties: 2, color: "#0f7a7a" },
400
+ away: { name: "USA", abbr: "USA", score: 2, penalties: 4, color: "#1c3f7a" },
401
+ home: { name: "Canada", abbr: "CAN", score: 2, penalties: 2, color: "#d52b1e" },
401
402
  status: "final-pens",
402
403
  ground: "metlife-stadium",
403
404
  });
@@ -496,7 +497,7 @@ console.log(svg.includes('viewBox="0 0 1200 675"'), svg.includes("Three ballpark
496
497
 
497
498
  <!-- score is home-away; home-score and away-score say it the other way -->
498
499
  <kyogijo-field sport="nba" size="compact" orientation="auto"
499
- home="Metro Bolts" away="Summit Peaks" score="112-108"
500
+ home="Japan" away="Australia" score="112-108"
500
501
  home-color="#c2410c" away-color="#14233f" status="final"></kyogijo-field>
501
502
  ```
502
503
 
@@ -511,7 +512,7 @@ import { createKyogijo, kyogijoProps } from "@johnmorrisdotca/kyogijo-stadiums/r
511
512
  // A component made from your React, which measures its box for orientation="auto":
512
513
  const Kyogijo = createKyogijo(React);
513
514
  export const Game = () => (
514
- <Kyogijo sport="nhl" orientation="auto" away={{ name: "Northern Owls", score: 3 }} home={{ name: "Lakeshore Anchors", score: 2 }} status="final" />
515
+ <Kyogijo sport="nhl" orientation="auto" away={{ name: "USA", score: 3 }} home={{ name: "Canada", score: 2 }} status="final" />
515
516
  );
516
517
 
517
518
  // Or props to spread onto your own element; nothing here imports React:
@@ -526,7 +527,7 @@ import "@johnmorrisdotca/kyogijo-stadiums/element/define";
526
527
  </script>
527
528
 
528
529
  <template>
529
- <kyogijo-field sport="nfl" orientation="auto" away="Harbour City Gulls" home="Prairie Ridge Bison" away-score="27" home-score="24" status="final" />
530
+ <kyogijo-field sport="nfl" orientation="auto" away="Mexico" home="USA" away-score="27" home-score="24" status="final" />
530
531
  </template>
531
532
  ```
532
533
 
@@ -540,12 +541,12 @@ Tell Vue the tag is a custom element with `compilerOptions.isCustomElement: (tag
540
541
  import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";
541
542
  export let home = 0;
542
543
  export let away = 0;
543
- $: svg = drawKyogijo({ sport: "nhl", away: { name: "Northern Owls", score: away }, home: { name: "Lakeshore Anchors", score: home } });
544
+ $: svg = drawKyogijo({ sport: "nhl", away: { name: "USA", score: away }, home: { name: "Canada", score: home } });
544
545
  </script>
545
546
 
546
547
  <!-- the string of SVG, or the element: either works -->
547
548
  {@html svg}
548
- <kyogijo-field sport="nhl" away="Northern Owls" home="Lakeshore Anchors" away-score={away} home-score={home} />
549
+ <kyogijo-field sport="nhl" away="USA" home="Canada" away-score={away} home-score={home} />
549
550
  ```
550
551
 
551
552
  A page that moves (`mountKyogijo`), a file written on a server and a frame for a page with no script are in [getting started](./docs/getting-started.md).
@@ -658,7 +659,7 @@ pnpm check # lint, types, every test, the build and the packed package
658
659
  pnpm test:package # pack, install and import it as somebody who installed it would
659
660
  pnpm test:demo # build the demo and the docs and play them in a real browser, at a phone's width and a desk's
660
661
  pnpm site # build the demo and the docs site into site/, as the Pages workflow publishes it
661
- pnpm screenshots:readme # take the README's pictures from the built demo, in light and dark
662
+ pnpm screenshots:readme # remake every README picture from the built demo, in light and dark, each on one of the family's backgrounds
662
663
  pnpm test:readme # run every example in the README and the docs against the built package
663
664
  pnpm docs:make # rewrite what the docs make from the source: the Japanese words, the leagues, the frames and units tables
664
665
  ```
@@ -684,5 +685,6 @@ The code is [MIT](./LICENSE) © John Morris. The ballparks' fence distances are
684
685
  | The fence distances of 94 ballparks | The English and Japanese Wikipedia articles of each, at the revision cited | Facts; the articles are CC BY-SA 4.0 and none of their text is used |
685
686
  | The Wikidata item of each ballpark | Wikidata, as linked from the cited article | CC0 |
686
687
  | 64 soccer grounds | English Wikipedia articles at the revision cited; Wikidata | Facts; CC BY-SA 4.0 articles, no text used; CC0 |
687
- | The demo's teams and emblems | Written for this package | MIT |
688
+ | The demo's countries and their logos | The names and codes of real countries; the maple leaf, the sun disc and the roundels are drawn for this package | MIT |
689
+ | The demo's country flags | [Hata](https://github.com/johnmorrisdotca/hata), a development dependency whose flags are loaded into the demo site with its licence and notice; the package itself draws none | MIT, and its flags' own licences in its NOTICE.md |
688
690
  | The demo's trophies, medals, balls and crests | [Dougu Sports](https://github.com/johnmorrisdotca/dougu-sports), a development dependency copied into the demo site with its licences; the package itself draws none | MIT, and its sources' licences in its NOTICE.md |
@@ -2,7 +2,7 @@
2
2
  // race (every runner on the curve of the lane, the stagger as the rules put it), and the attempts of a field event as marks in the sector or the pit with the best mark picked out. Written for this
3
3
  // package from the Track and Field Facilities Manual (2019, 2.2.1.6) and Book C2.1's Technical Rules (14, 17, 25 to 38); nothing of any other package is used. The flags are the caller's: an SVG
4
4
  // document as text, or an address, as a team's logo is.
5
- import { assemble, clean, drawingOptions, languageOf, round, wordsOf } from "./charts.js";
5
+ import { assemble, clean, drawingOptions, entryFlag, languageOf, round, wordsOf } from "./charts.js";
6
6
  import { athleticsPlan } from "./athletics/plan.js";
7
7
  import { raceById, fieldEventById } from "./athletics/events.js";
8
8
  import { fieldEventName } from "./athletics/describe.js";
@@ -101,9 +101,10 @@ export function laneDraw(entries, options = {}) {
101
101
  const back = (d) => [start.x - fx * d, start.y - fy * d];
102
102
  const [nx, ny] = back(nameAt);
103
103
  names.push(clean({ x: nx, y: ny, text: e.name, anchor: "end", size: nameSize, rotate: portrait ? -90 : 0, title: e.country === undefined ? undefined : `${e.name}, ${e.country}` }));
104
- if (e.flag !== undefined) {
104
+ const flag = entryFlag(e, options);
105
+ if (flag !== undefined) {
105
106
  const [px, py] = back(flagAt);
106
- flags.push(clean({ x: px, y: py, shape: "logo", logo: e.flag, size: flagSide / 1.8, title: e.country }));
107
+ flags.push(clean({ x: px, y: py, shape: "logo", logo: flag, size: flagSide / 1.8, title: e.country }));
107
108
  }
108
109
  }
109
110
  const at = { from: "athletics", units: "m" };
@@ -41,7 +41,7 @@ export declare function curlingScore(stones: readonly CurlingStone[], options?:
41
41
  * { x: 1.9, y: 1.1, team: "away", number: 7 },
42
42
  * { x: 0, y: -12, team: "away", number: 3 },
43
43
  * ],
44
- * { end: 6, hammer: "home", names: { home: "Prairie Ridge", away: "Harbour City" } },
44
+ * { end: 6, hammer: "home", names: { home: "Canada", away: "Japan" } },
45
45
  * );
46
46
  * console.log(chart.totals.points, chart.totals.scoring, chart.title);
47
47
  * // 2 home Curling stones, End 6
@@ -109,7 +109,7 @@ const LOOKS = { stone: {}, counting: { hollow: true }, "shot-rock": { hollow: tr
109
109
  * { x: 1.9, y: 1.1, team: "away", number: 7 },
110
110
  * { x: 0, y: -12, team: "away", number: 3 },
111
111
  * ],
112
- * { end: 6, hammer: "home", names: { home: "Prairie Ridge", away: "Harbour City" } },
112
+ * { end: 6, hammer: "home", names: { home: "Canada", away: "Japan" } },
113
113
  * );
114
114
  * console.log(chart.totals.points, chart.totals.scoring, chart.title);
115
115
  * // 2 home Curling stones, End 6
package/dist/charts.d.ts CHANGED
@@ -42,6 +42,14 @@ export interface KeyPlace {
42
42
  export declare const isKey: (layer: Layer) => boolean;
43
43
  /** The key of a chart as data, from its entries and looks. */
44
44
  export declare function keyItems(entries: readonly KeyEntry[], looks: Readonly<Record<string, Look>>): KeyItem[];
45
+ /**
46
+ * The picture of an entry's flag: the `flag` it gives, else the flag of its `country` code by the renderer of flags the chart's `surface.flags` (or `useFlags`) plugs in, in its own proportions;
47
+ * `undefined` where there is none, so that a chart without a renderer lays out as it always did.
48
+ */
49
+ export declare function entryFlag(entry: {
50
+ flag?: string;
51
+ country?: string;
52
+ }, options: ChartOptions): string | undefined;
45
53
  /** Put a chart together: the options, the layers and the ways to draw them. */
46
54
  export declare function assemble<T>(options: SurfaceOptions, layers: Layer[], parts: {
47
55
  title: string;
package/dist/charts.js CHANGED
@@ -8,7 +8,9 @@ import { fromSurface, frameByName, toSurface } from "./frames.js";
8
8
  import { zoneCounts } from "./heat.js";
9
9
  import { isPortrait } from "./common.js";
10
10
  import { envFor, isNum, place, unitOfLayer } from "./layers.env.js";
11
+ import { withFlags } from "./flags-source.js";
11
12
  import { layerTable } from "./layers.js";
13
+ import { flagPicture } from "./logo.js";
12
14
  import { outlineOf } from "./outline.js";
13
15
  import { KYOGIJO_STRINGS, fill } from "./strings.js";
14
16
  import { textWidth } from "./text.js";
@@ -102,6 +104,17 @@ export const isKey = (layer) => layer.id === "key-marks" || layer.id === "key-te
102
104
  export function keyItems(entries, looks) {
103
105
  return entries.map((e) => ({ outcome: e.outcome ?? "", label: e.label, shape: looks[e.outcome ?? ""]?.shape ?? "circle", hollow: looks[e.outcome ?? ""]?.hollow === true }));
104
106
  }
107
+ /**
108
+ * The picture of an entry's flag: the `flag` it gives, else the flag of its `country` code by the renderer of flags the chart's `surface.flags` (or `useFlags`) plugs in, in its own proportions;
109
+ * `undefined` where there is none, so that a chart without a renderer lays out as it always did.
110
+ */
111
+ export function entryFlag(entry, options) {
112
+ if (entry.flag !== undefined)
113
+ return entry.flag;
114
+ if (entry.country === undefined)
115
+ return undefined;
116
+ return withFlags(options.surface?.flags, () => flagPicture(entry.country, "rect", 24, options.surface?.theme));
117
+ }
105
118
  /** Put a chart together: the options, the layers and the ways to draw them. */
106
119
  export function assemble(options, layers, parts) {
107
120
  const all = { ...options, layers };
@@ -2,7 +2,7 @@
2
2
  // with their medals, times and splits, a replay of the race (every skater on his own way round the track, the lane changed once a lap), and the elements of a figure skating programme as marks on the ice.
3
3
  // Written for this package from the ISU's Special Regulations and Technical Rules for speed skating (Rules 203, 227, 253, 254 and 280) and short track speed skating (Rule 280); nothing of any other package
4
4
  // is used. The flags are the caller's: an SVG document as text, or an address, as a team's logo is.
5
- import { assemble, clean, drawingOptions, languageOf, round, wordsOf } from "./charts.js";
5
+ import { assemble, clean, drawingOptions, entryFlag, languageOf, round, wordsOf } from "./charts.js";
6
6
  import { esc } from "./format.js";
7
7
  import { fill } from "./strings.js";
8
8
  import { ELEMENT_KINDS, ELEMENT_NAMES, raceById } from "./skating/events.js";
@@ -122,11 +122,12 @@ export function skatingPairs(pairs, options = {}) {
122
122
  const back = (d) => [base.x - fx * d, base.y - fy * d];
123
123
  const [bx, by] = back(1.6);
124
124
  bands.push({ x: bx, y: by, shape: "circle", size: 1.2, color: ARMBAND[laneName], title: laneName === "inner" ? w.data.lanes.inner : w.data.lanes.outer });
125
- if (entry.flag !== undefined) {
125
+ const flag = entryFlag(entry, options);
126
+ if (flag !== undefined) {
126
127
  const [px, py] = back(3.6);
127
- flags.push(clean({ x: px, y: py, shape: "logo", logo: entry.flag, size: 1.6, title: entry.country }));
128
+ flags.push(clean({ x: px, y: py, shape: "logo", logo: flag, size: 1.6, title: entry.country }));
128
129
  }
129
- const [nx, ny] = back(entry.flag !== undefined ? 5.4 : 3);
130
+ const [nx, ny] = back(flag !== undefined ? 5.4 : 3);
130
131
  names.push(clean({ x: nx, y: ny, text: entry.name, anchor: fx < 0 ? "start" : "end", size: 1.9, title: entry.country === undefined ? undefined : `${entry.name}, ${entry.country}` }));
131
132
  }
132
133
  const layers = [];
@@ -189,9 +190,10 @@ export function skatingGrid(starters, options = {}) {
189
190
  const spot = spots[s.position - 1];
190
191
  // The skaters go left along the top straight and right along the bottom one: the names stand behind the line.
191
192
  const dir = top ? -1 : 1;
192
- names.push(clean({ x: spot.x - dir * (s.flag === undefined ? 1.2 : 2.6), y: spot.y, text: s.name, anchor: top ? "start" : "end", size: 0.9, title: s.country === undefined ? undefined : `${s.name}, ${s.country}` }));
193
- if (s.flag !== undefined)
194
- flags.push(clean({ x: spot.x - dir * 1.4, y: spot.y, shape: "logo", logo: s.flag, size: 0.8, title: s.country }));
193
+ const flag = entryFlag(s, opts);
194
+ names.push(clean({ x: spot.x - dir * (flag === undefined ? 1.2 : 2.6), y: spot.y, text: s.name, anchor: top ? "start" : "end", size: 0.9, title: s.country === undefined ? undefined : `${s.name}, ${s.country}` }));
195
+ if (flag !== undefined)
196
+ flags.push(clean({ x: spot.x - dir * 1.4, y: spot.y, shape: "logo", logo: flag, size: 0.8, title: s.country }));
195
197
  }
196
198
  const layers = [];
197
199
  if (flags.length > 0)
package/dist/draw.d.ts CHANGED
@@ -39,11 +39,11 @@ export declare function describe(o: SurfaceOptions | ScoreOptions): {
39
39
  * import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";
40
40
  * const svg = drawKyogijo({
41
41
  * sport: "nhl",
42
- * away: { name: "Harbour City Gulls", abbr: "HCG", score: 3, color: "#1f5fa8" },
43
- * home: { name: "Prairie Ridge Bison", abbr: "PRB", score: 2, color: "#b5452c" },
42
+ * away: { name: "USA", abbr: "USA", score: 3, color: "#1c3f7a" },
43
+ * home: { name: "Canada", abbr: "CAN", score: 2, color: "#d52b1e" },
44
44
  * status: "final-ot",
45
45
  * });
46
- * console.log(svg.startsWith("<svg"), svg.includes("Harbour City Gulls"));
46
+ * console.log(svg.startsWith("<svg"), svg.includes("USA"));
47
47
  * // true true
48
48
  * ```
49
49
  */
package/dist/draw.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { ballparkDrawn, ballparkFor, ballparkSentences } from "./ballpark.js";
2
- import { inkOn, safeColour } from "./colour.js";
2
+ import { inkOn, safeColour, safePicture } from "./colour.js";
3
3
  import { withEmblems } from "./emblems-source.js";
4
- import { safeLogo } from "./logo.js";
4
+ import { flagPicture, safeLogo } from "./logo.js";
5
+ import { flagDocument, flagTheme, withFlags } from "./flags-source.js";
5
6
  import { drawingId, feetFence, isPortrait, lengthUnit, safeClass } from "./common.js";
6
7
  import { el, esc, num } from "./format.js";
7
8
  import { fieldAttributes } from "./field.data.js";
@@ -534,10 +535,13 @@ function roundOf(team, markShape) {
534
535
  return undefined;
535
536
  return { round: true, fit: team.markFit === "contain" ? "contain" : undefined, color: safeColour(team.color), ink: safeColour(team.textColor) };
536
537
  }
538
+ /** The width in pixels a flag is asked for in a team's mark (a nominal one: a drawing scales). */
539
+ const FLAG_MARK_SIZE = 48;
537
540
  function teamView(team, side, role, winner, uppercase, sport, markShape, theme) {
538
541
  const name = String(team.name ?? "");
539
542
  const abbr = (team.abbr !== undefined && team.abbr.trim() !== "" ? team.abbr.trim() : abbreviate(name)).slice(0, 5);
540
543
  const written = fieldScoreText(sport, team) ?? budoScoreText(sport, team);
544
+ const round = roundOf(team, markShape);
541
545
  const score = written ?? (team.score === undefined || team.score === null || String(team.score).trim() === "" ? "–" : String(team.score));
542
546
  return {
543
547
  side,
@@ -545,8 +549,9 @@ function teamView(team, side, role, winner, uppercase, sport, markShape, theme)
545
549
  name: uppercase ? capitals(name) : name,
546
550
  abbr,
547
551
  score,
548
- logo: safeLogo(team.logo, { color: team.color, accent: team.textColor, initials: abbr.slice(0, 3), theme }),
549
- ...roundOf(team, markShape),
552
+ // The flag a team's country code names, when a renderer of flags is plugged in, is its logo: round in a round mark, in its own proportions otherwise.
553
+ logo: flagPicture(team.flag, round === undefined ? "rect" : "round", FLAG_MARK_SIZE, theme) ?? safeLogo(team.logo, { color: team.color, accent: team.textColor, initials: abbr.slice(0, 3), theme }),
554
+ ...round,
550
555
  state: stateOf(winner, role),
551
556
  ends: Array.isArray(team.ends) ? team.ends.map(endText) : undefined,
552
557
  hammer: team.hammer === true ? true : undefined,
@@ -561,22 +566,27 @@ function teamView(team, side, role, winner, uppercase, sport, markShape, theme)
561
566
  };
562
567
  }
563
568
  /** A team as the pageant lays it out. */
564
- function pageantTeam(view, team) {
565
- return { side: view.side, role: view.role, name: view.name, abbr: view.abbr, state: view.state, href: view.logo, fit: team.markFit === "contain" ? "contain" : "cover", ratio: ratioOf(team), color: safeColour(team.color), ink: safeColour(team.textColor) };
569
+ function pageantTeam(view, team, style, theme) {
570
+ // A carpet is a flag laid flat, in its own proportions; a stage is a round disc, so a flag is asked for round there.
571
+ const flag = flagDocument(team.flag, { shape: style === "stage" ? "round" : "rect", size: FLAG_PAGEANT_SIZE, theme: flagTheme(theme) });
572
+ const picture = safePicture(flag);
573
+ return { side: view.side, role: view.role, name: view.name, abbr: view.abbr, state: view.state, href: picture ?? view.logo, fit: team.markFit === "contain" ? "contain" : "cover", ratio: ratioOf({ logo: picture === undefined ? team.logo : flag, logoRatio: team.logoRatio }), color: safeColour(team.color), ink: safeColour(team.textColor) };
566
574
  }
575
+ /** The width in pixels a flag is asked for when a pageant lays it out large (a nominal one: a drawing scales). */
576
+ const FLAG_PAGEANT_SIZE = 240;
567
577
  /** True when the drawing is asked to be small: its `width` is under 320 pixels. The pageant then leaves out its fabric, hairlines and name pills. */
568
578
  function tiny(width) {
569
579
  const px = typeof width === "number" ? width : typeof width === "string" && /^\d+(?:\.\d+)?(?:px)?$/.test(width.trim()) ? Number.parseFloat(width) : undefined;
570
580
  return px !== undefined && Number.isFinite(px) && px < 320;
571
581
  }
572
582
  /** The teams that fill the first and the second place of a surface: a diamond's outfield is the visitors' and its infield the home team's, whichever side each is on. */
573
- function pageantPair(surface, t) {
574
- const l = pageantTeam(t.left, t.leftTeam);
575
- const r = pageantTeam(t.right, t.rightTeam);
583
+ function pageantPair(surface, t, style, theme) {
584
+ const l = pageantTeam(t.left, t.leftTeam, style, theme);
585
+ const r = pageantTeam(t.right, t.rightTeam, style, theme);
576
586
  return surface.pageant?.byRole === true && l.role === "home" ? [r, l] : [l, r];
577
587
  }
578
588
  function pageantParts(o, surface, p, t) {
579
- const [first, second] = pageantPair(surface, t);
589
+ const [first, second] = pageantPair(surface, t, p.style, o.theme);
580
590
  const layout = pageantLayout({ pageant: p, surface, outline: outlineOf(o), left: first, right: second, turned: surface.turned, sport: t.sport, plate: t.plate });
581
591
  if (layout === undefined)
582
592
  return undefined;
@@ -802,16 +812,16 @@ export function describe(o) {
802
812
  * import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";
803
813
  * const svg = drawKyogijo({
804
814
  * sport: "nhl",
805
- * away: { name: "Harbour City Gulls", abbr: "HCG", score: 3, color: "#1f5fa8" },
806
- * home: { name: "Prairie Ridge Bison", abbr: "PRB", score: 2, color: "#b5452c" },
815
+ * away: { name: "USA", abbr: "USA", score: 3, color: "#1c3f7a" },
816
+ * home: { name: "Canada", abbr: "CAN", score: 2, color: "#d52b1e" },
807
817
  * status: "final-ot",
808
818
  * });
809
- * console.log(svg.startsWith("<svg"), svg.includes("Harbour City Gulls"));
819
+ * console.log(svg.startsWith("<svg"), svg.includes("USA"));
810
820
  * // true true
811
821
  * ```
812
822
  */
813
823
  export function drawKyogijo(o) {
814
- return withEmblems(o.emblems, () => drawnKyogijo(o));
824
+ return withEmblems(o.emblems, () => withFlags(o.flags, () => drawnKyogijo(o)));
815
825
  }
816
826
  function drawnKyogijo(o) {
817
827
  if (o.host !== undefined && o.range !== undefined)
@@ -906,7 +916,7 @@ function drawnKyogijo(o) {
906
916
  if (pageant !== undefined && pageant.score === "auto") {
907
917
  let score = stripped ? "strip" : "centre";
908
918
  if (!stripped && isScore(o) && left !== undefined && right !== undefined && leftTeam !== undefined && rightTeam !== undefined && sized === "full") {
909
- const [first, second] = pageantPair(surface, { left, right, leftTeam, rightTeam });
919
+ const [first, second] = pageantPair(surface, { left, right, leftTeam, rightTeam }, pageant.style, o.theme);
910
920
  score = autoScore({ pageant, surface, outline: outlineOf(o), left: first, right: second, turned: surface.turned, sport, plate: true });
911
921
  }
912
922
  pageant = { ...pageant, score };
@@ -1,3 +1,5 @@
1
1
  export { KYOGIJO_ATTRIBUTES, KYOGIJO_TAG, KyogijoField, defineKyogijoField, optionsFromAttributes, replaySettingsFromAttributes, turnSettingsFromAttributes, turnWanted } from "./element.ts";
2
2
  export { useEmblems } from "./emblems-source.ts";
3
3
  export type { EmblemRenderer } from "./emblems-source.ts";
4
+ export { useFlags } from "./flags-source.ts";
5
+ export type { FlagRenderer, FlagRequest, FlagShape } from "./flags-source.ts";
@@ -1,3 +1,4 @@
1
1
  // The custom element's class and its registration function; importing this entry registers nothing.
2
2
  export { KYOGIJO_ATTRIBUTES, KYOGIJO_TAG, KyogijoField, defineKyogijoField, optionsFromAttributes, replaySettingsFromAttributes, turnSettingsFromAttributes, turnWanted } from "./element.js";
3
3
  export { useEmblems } from "./emblems-source.js";
4
+ export { useFlags } from "./flags-source.js";
package/dist/element.d.ts CHANGED
@@ -6,7 +6,7 @@ import type { ScoreOptions, SurfaceOptions } from "./types.ts";
6
6
  /** The tag of the element. */
7
7
  export declare const KYOGIJO_TAG = "kyogijo-field";
8
8
  /** The attributes the element reads. */
9
- export declare const KYOGIJO_ATTRIBUTES: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed"];
9
+ export declare const KYOGIJO_ATTRIBUTES: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-flag", "away-flag", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed"];
10
10
  /** The settings of a 3D view an element's attributes make: `turn-view` names the viewpoint it opens on, `turn-controls="false"` and `turn-uprights="false"` leave the buttons and what stands on the surface out, `turn-score="floor"` leaves the score panel on the floor, `turn-touch="turn"` keeps every touch for the view, `turn-venue="false"` leaves out the stands and the room (they are raised for a drawing with a crowd and for a dojo), `turn-roof` puts a roof or canopy over the stands, `turn-autoplay` starts the auto-turn (`force` even for a reader who prefers reduced motion) and `turn-speed` is its degrees a second. */
11
11
  export declare function turnSettingsFromAttributes(read: (name: string) => string | null, base?: TurnSettings): TurnSettings;
12
12
  /** Whether an element's `turn` attribute asks for the 3D view: present, and not `false`. */
@@ -24,7 +24,7 @@ export declare function optionsFromAttributes(read: (name: string) => string | n
24
24
  declare const Base: typeof HTMLElement;
25
25
  export declare class KyogijoField extends Base {
26
26
  #private;
27
- static observedAttributes: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed"];
27
+ static observedAttributes: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-flag", "away-flag", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed"];
28
28
  /** The options given as a property: an object, laid under the attributes. */
29
29
  get options(): Partial<ScoreOptions> | undefined;
30
30
  set options(value: Partial<ScoreOptions> | undefined);
package/dist/element.js CHANGED
@@ -22,7 +22,7 @@ export const KYOGIJO_TAG = "kyogijo-field";
22
22
  export const KYOGIJO_ATTRIBUTES = [
23
23
  "sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase",
24
24
  "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks",
25
- "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-color", "away-color",
25
+ "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-flag", "away-flag", "home-color", "away-color",
26
26
  "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options",
27
27
  "loop", "speed", "autoplay", "controls", "trail",
28
28
  "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed",
@@ -229,6 +229,9 @@ export function optionsFromAttributes(read, base) {
229
229
  const logo = read(`${role}-logo`);
230
230
  if (logo !== null)
231
231
  out.logo = logo;
232
+ const flag = read(`${role}-flag`);
233
+ if (flag !== null)
234
+ out.flag = flag;
232
235
  const color = read(`${role}-color`);
233
236
  if (color !== null)
234
237
  out.color = color;
@@ -0,0 +1,37 @@
1
+ /** How a flag is framed: `round` for a circle, `square` as wide as it is tall, `rect` in its own proportions. */
2
+ export type FlagShape = "round" | "square" | "rect";
3
+ /** What a drawing asks a `flags` renderer for. */
4
+ export interface FlagRequest {
5
+ shape: FlagShape;
6
+ /** The width in pixels the flag is drawn at, nominally (a drawing scales, so this is the size of a typical use): the diameter of a round flag. */
7
+ size: number;
8
+ /** `light` or `dark` for a drawing in that look, else `inherit`. */
9
+ theme: "inherit" | "light" | "dark";
10
+ }
11
+ /**
12
+ * A function from a country code and a request to an SVG string, or `null` or `undefined` for a code it has no flag for. It must be synchronous: a drawing is a pure function of its
13
+ * options. `@johnmorrisdotca/hata`'s `flag()` is asynchronous, so load the flags first (`await flag(code, { shape: "round" })` for each code) and pass a lookup.
14
+ */
15
+ export type FlagRenderer = (code: string, request: FlagRequest) => string | null | undefined;
16
+ /**
17
+ * Plug a renderer of country flags into kyogijo, for every drawing on the page: after this a team's `flag: "CA"` is drawn. Call it once, at start-up. Without one a team's `flag` is
18
+ * ignored and its `logo` (or its initials) is drawn. `useFlags(undefined)` unplugs it.
19
+ * @example
20
+ * ```ts
21
+ * import { useFlags } from "@johnmorrisdotca/kyogijo-stadiums";
22
+ * const loaded = { round: { CA: "<svg viewBox='0 0 1 1'>...</svg>" } } as Record<string, Record<string, string>>;
23
+ * useFlags((code, { shape }) => loaded[shape]?.[code.toUpperCase()]);
24
+ * ```
25
+ */
26
+ export declare function useFlags(render: FlagRenderer | undefined): void;
27
+ /** Run a drawing with a renderer for that drawing alone (the `flags` option), putting back whatever was there. Without a renderer it runs as it is. */
28
+ export declare function withFlags<T>(render: FlagRenderer | undefined, draw: () => T): T;
29
+ /** The renderer in use: the drawing's own, else the page's, else none. */
30
+ export declare function flagRenderer(): FlagRenderer | undefined;
31
+ /**
32
+ * The flag of a country code as an SVG document, drawn by the renderer in use, or `undefined`: no renderer, a value that does not look like a code, a code the renderer has no flag for,
33
+ * a renderer that throws, or one that returns something that is not an `<svg>`. It never throws.
34
+ */
35
+ export declare function flagDocument(code: unknown, request: FlagRequest): string | undefined;
36
+ /** The theme a drawing tells a renderer: `light` or `dark` when the options say so, else `inherit`. */
37
+ export declare const flagTheme: (theme: unknown) => FlagRequest["theme"];
@@ -0,0 +1,60 @@
1
+ // Where kyogijo gets country flags from: a renderer that the page plugs in, so that kyogijo bundles no flag and keeps zero dependencies. The renderer is a synchronous function from a
2
+ // country code and a request to an SVG string; `@johnmorrisdotca/hata` draws the flags, and its `flag()` is asynchronous, so a page loads the codes it needs first and plugs in a lookup
3
+ // (docs/flags.md). `useFlags(render)` plugs it in for the page, `flags: render` for one drawing. The shape of the renderer is the one Taisen Brackets takes, so one adapter serves both.
4
+ // This module knows nothing of any flag: it asks the renderer, checks what it gives back, and returns an SVG document or nothing.
5
+ let plugged;
6
+ let scoped;
7
+ /**
8
+ * Plug a renderer of country flags into kyogijo, for every drawing on the page: after this a team's `flag: "CA"` is drawn. Call it once, at start-up. Without one a team's `flag` is
9
+ * ignored and its `logo` (or its initials) is drawn. `useFlags(undefined)` unplugs it.
10
+ * @example
11
+ * ```ts
12
+ * import { useFlags } from "@johnmorrisdotca/kyogijo-stadiums";
13
+ * const loaded = { round: { CA: "<svg viewBox='0 0 1 1'>...</svg>" } } as Record<string, Record<string, string>>;
14
+ * useFlags((code, { shape }) => loaded[shape]?.[code.toUpperCase()]);
15
+ * ```
16
+ */
17
+ export function useFlags(render) {
18
+ plugged = typeof render === "function" ? render : undefined;
19
+ }
20
+ /** Run a drawing with a renderer for that drawing alone (the `flags` option), putting back whatever was there. Without a renderer it runs as it is. */
21
+ export function withFlags(render, draw) {
22
+ if (typeof render !== "function")
23
+ return draw();
24
+ const before = scoped;
25
+ scoped = render;
26
+ try {
27
+ return draw();
28
+ }
29
+ finally {
30
+ scoped = before;
31
+ }
32
+ }
33
+ /** The renderer in use: the drawing's own, else the page's, else none. */
34
+ export function flagRenderer() {
35
+ return scoped ?? plugged;
36
+ }
37
+ /** The look of a country or region code: letters and digits in one or two parts (`CA`, `usa`, `GB-ENG`, `JP-13`). */
38
+ const CODE = /^[A-Za-z0-9]{2,8}(?:-[A-Za-z0-9]{1,8})?$/;
39
+ /**
40
+ * The flag of a country code as an SVG document, drawn by the renderer in use, or `undefined`: no renderer, a value that does not look like a code, a code the renderer has no flag for,
41
+ * a renderer that throws, or one that returns something that is not an `<svg>`. It never throws.
42
+ */
43
+ export function flagDocument(code, request) {
44
+ const render = flagRenderer();
45
+ if (render === undefined || typeof code !== "string")
46
+ return undefined;
47
+ const text = code.trim();
48
+ if (!CODE.test(text))
49
+ return undefined;
50
+ let svg;
51
+ try {
52
+ svg = render(text, { shape: request.shape, size: Math.round(request.size), theme: request.theme });
53
+ }
54
+ catch {
55
+ return undefined;
56
+ }
57
+ return typeof svg === "string" && /^\s*(?:<\?xml|<svg)\b/i.test(svg) ? svg : undefined;
58
+ }
59
+ /** The theme a drawing tells a renderer: `light` or `dark` when the options say so, else `inherit`. */
60
+ export const flagTheme = (theme) => (theme === "light" || theme === "dark" ? theme : "inherit");
package/dist/index.d.ts CHANGED
@@ -4,6 +4,8 @@ export { inkOn, luminance, rgbOf, safeColour, safePicture } from "./colour.ts";
4
4
  export { safeLogo } from "./logo.ts";
5
5
  export { useEmblems } from "./emblems-source.ts";
6
6
  export type { EmblemDrawOptions, EmblemId, EmblemRef, EmblemRenderer, EmblemStyleName } from "./emblems-source.ts";
7
+ export { useFlags } from "./flags-source.ts";
8
+ export type { FlagRenderer, FlagRequest, FlagShape } from "./flags-source.ts";
7
9
  export { OUTCOMES, drawLayers, layerTable } from "./layers.ts";
8
10
  export { RANGES } from "./ranges.names.ts";
9
11
  export { BACKGROUND_OPACITY, BACKGROUND_PATTERNS, KYOGIJO_BACKGROUND_STYLE } from "./background.ts";
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export { HOME_FIRST, HOME_FIRST_LEAGUES, homeSideFor } from "./homeside.js";
4
4
  export { inkOn, luminance, rgbOf, safeColour, safePicture } from "./colour.js";
5
5
  export { safeLogo } from "./logo.js";
6
6
  export { useEmblems } from "./emblems-source.js";
7
+ export { useFlags } from "./flags-source.js";
7
8
  export { OUTCOMES, drawLayers, layerTable } from "./layers.js";
8
9
  export { RANGES } from "./ranges.names.js";
9
10
  export { BACKGROUND_OPACITY, BACKGROUND_PATTERNS, KYOGIJO_BACKGROUND_STYLE } from "./background.js";
@@ -1,6 +1,6 @@
1
1
  // What every kind of data layer is drawn against: the drawing's id, its unit and outline, the words, and what a layer made. Kept apart
2
2
  // from layers.ts so that the heat maps, which are written in files of their own, can use it without importing the file that imports them.
3
- import { safeLogo } from "./logo.js";
3
+ import { flagPicture, safeLogo } from "./logo.js";
4
4
  import { esc } from "./format.js";
5
5
  import { drawingId, isPortrait, lengthUnit } from "./common.js";
6
6
  import { fromSurface, toSurface } from "./frames.js";
@@ -104,7 +104,10 @@ export function envFor(o, turned, range, upright, zone) {
104
104
  cropped: range !== undefined,
105
105
  base: Math.max((range ?? outline.box).w, (range ?? outline.box).h) * 0.013,
106
106
  words: KYOGIJO_STRINGS[language],
107
- logos: { home: safeLogo(teams.home?.logo, { color: teams.home?.color, accent: teams.home?.textColor }), away: safeLogo(teams.away?.logo, { color: teams.away?.color, accent: teams.away?.textColor }) },
107
+ logos: {
108
+ home: flagPicture(teams.home?.flag, "rect", 48, o.theme) ?? safeLogo(teams.home?.logo, { color: teams.home?.color, accent: teams.home?.textColor }),
109
+ away: flagPicture(teams.away?.flag, "rect", 48, o.theme) ?? safeLogo(teams.away?.logo, { color: teams.away?.color, accent: teams.away?.textColor }),
110
+ },
108
111
  marks: o.marks === true || o.pointer === true,
109
112
  zone: zone ?? zonesOf(o),
110
113
  };
package/dist/layers.js CHANGED
@@ -5,6 +5,7 @@
5
5
  // either is used.
6
6
  import { safeColour } from "./colour.js";
7
7
  import { withEmblems } from "./emblems-source.js";
8
+ import { withFlags } from "./flags-source.js";
8
9
  import { safeLogo } from "./logo.js";
9
10
  import { FRAMES } from "./frames.js";
10
11
  import { KYOGIJO_HEAT_STYLE, KYOGIJO_TEAM_STYLE } from "./style.js";
@@ -358,7 +359,7 @@ function summarise(layer, made, words, stop, gap) {
358
359
  }
359
360
  /** The layers of a drawing as markup, and a sentence for each. `turned` says whether the surface group is turned a quarter. */
360
361
  export function renderLayers(o, layers, turned, range, upright, zone) {
361
- return withEmblems(o.emblems, () => renderedLayers(o, layers, turned, range, upright, zone));
362
+ return withEmblems(o.emblems, () => withFlags(o.flags, () => renderedLayers(o, layers, turned, range, upright, zone)));
362
363
  }
363
364
  function renderedLayers(o, layers, turned, range, upright, zone) {
364
365
  if (layers === undefined || layers.length === 0)
package/dist/logo.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type FlagShape } from "./flags-source.ts";
1
2
  /** What a caller says about the team an emblem stands for: its colours and letters, so a crest id takes them; and the theme of the drawing it goes in. */
2
3
  export interface EmblemContext {
3
4
  color?: string;
@@ -23,3 +24,8 @@ export declare function emblemDocument(value: unknown, context?: EmblemContext):
23
24
  * ```
24
25
  */
25
26
  export declare function safeLogo(value: unknown, context?: EmblemContext): string | undefined;
27
+ /**
28
+ * The picture of a country's flag as it may be written into an image's `href`, or `undefined` when no renderer of flags is plugged in (`useFlags`, or the `flags` option), it has no flag for the code, or
29
+ * `code` is not a code. `size` is the nominal width in pixels the renderer is told; `theme` is the drawing's.
30
+ */
31
+ export declare function flagPicture(code: unknown, shape: FlagShape, size: number, theme?: unknown): string | undefined;
package/dist/logo.js CHANGED
@@ -2,6 +2,7 @@
2
2
  // (`useEmblems`, or the `emblems` option), the id of one (`"trophy:cup"`, `"crest:shield"`, `"sport:hockey/line"`). The result is an address that may be written into an image's `href`, or `undefined`.
3
3
  import { safePicture } from "./colour.js";
4
4
  import { GROUPED_ID, emblemRenderer, renderedEmblem } from "./emblems-source.js";
5
+ import { flagDocument, flagTheme } from "./flags-source.js";
5
6
  let told = false;
6
7
  /** Once, in development: an id with its group was given and nothing is plugged in to draw it. */
7
8
  function hint(value) {
@@ -45,3 +46,10 @@ export function safeLogo(value, context) {
45
46
  hint(value);
46
47
  return picture;
47
48
  }
49
+ /**
50
+ * The picture of a country's flag as it may be written into an image's `href`, or `undefined` when no renderer of flags is plugged in (`useFlags`, or the `flags` option), it has no flag for the code, or
51
+ * `code` is not a code. `size` is the nominal width in pixels the renderer is told; `theme` is the drawing's.
52
+ */
53
+ export function flagPicture(code, shape, size, theme) {
54
+ return safePicture(flagDocument(code, { shape, size, theme: flagTheme(theme) }));
55
+ }
package/dist/mount.d.ts CHANGED
@@ -44,11 +44,11 @@ export declare function containerAspect(host: HTMLElement, breakpoint?: number):
44
44
  * const card = mountKyogijo(document.querySelector("#game")!, {
45
45
  * sport: "nhl",
46
46
  * orientation: "auto",
47
- * away: { name: "Harbour City Gulls", score: 1 },
48
- * home: { name: "Prairie Ridge Bison", score: 0 },
47
+ * away: { name: "USA", score: 1 },
48
+ * home: { name: "Canada", score: 0 },
49
49
  * status: "live",
50
50
  * });
51
- * card.update({ sport: "nhl", orientation: "auto", away: { name: "Harbour City Gulls", score: 2 }, home: { name: "Prairie Ridge Bison", score: 0 } });
51
+ * card.update({ sport: "nhl", orientation: "auto", away: { name: "USA", score: 2 }, home: { name: "Canada", score: 0 } });
52
52
  * ```
53
53
  */
54
54
  export declare function mountKyogijo(host: HTMLElement, options: SurfaceOptions | ScoreOptions, settings?: MountSettings): KyogijoMount;
package/dist/mount.js CHANGED
@@ -59,11 +59,11 @@ export function containerAspect(host, breakpoint = 560) {
59
59
  * const card = mountKyogijo(document.querySelector("#game")!, {
60
60
  * sport: "nhl",
61
61
  * orientation: "auto",
62
- * away: { name: "Harbour City Gulls", score: 1 },
63
- * home: { name: "Prairie Ridge Bison", score: 0 },
62
+ * away: { name: "USA", score: 1 },
63
+ * home: { name: "Canada", score: 0 },
64
64
  * status: "live",
65
65
  * });
66
- * card.update({ sport: "nhl", orientation: "auto", away: { name: "Harbour City Gulls", score: 2 }, home: { name: "Prairie Ridge Bison", score: 0 } });
66
+ * card.update({ sport: "nhl", orientation: "auto", away: { name: "USA", score: 2 }, home: { name: "Canada", score: 0 } });
67
67
  * ```
68
68
  */
69
69
  export function mountKyogijo(host, options, settings = {}) {
@@ -2,7 +2,7 @@
2
2
  // split pace bars in the lanes. Drawn in feet in the frame of a pool lying wide; a pool lying tall turns it with the pool, so that the labels lie along the lanes, and only the numbers in the discs are
3
3
  // turned back upright. Nothing here is a rule of the sport: the sizes are ours.
4
4
  import { safeColour } from "./colour.js";
5
- import { safeLogo } from "./logo.js";
5
+ import { flagPicture, safeLogo } from "./logo.js";
6
6
  import { el, esc, num } from "./format.js";
7
7
  import { feet } from "./pool.js";
8
8
  import { STATUS_TEXT, formatTime, pacePer100, splitMetres } from "./pool.race.js";
@@ -45,8 +45,10 @@ function disc(o, cx, cy, text, cls, fill) {
45
45
  const size = text.length > 2 ? r * 0.95 : r * 1.25;
46
46
  return el("circle", { class: cls, cx, cy, r, fill }) + textOn(o.portrait, cx, cy + size * 0.36, text, { size, anchor: "middle", cls: "ky-pl-dn", weight: 800 });
47
47
  }
48
+ /** The picture of a swimmer's flag: the `flag` given, else the flag of the `country` code (in its own proportions, by the renderer of flags in use). */
49
+ const flagOf = (row) => safeLogo(row.flag) ?? flagPicture(row.country, "rect", 24);
48
50
  function flagMarkup(row, x, cy, w, h) {
49
- const logo = safeLogo(row.flag);
51
+ const logo = flagOf(row);
50
52
  if (logo === undefined)
51
53
  return "";
52
54
  return el("image", { class: "ky-logo", href: logo, x, y: cy - h / 2, width: w, height: h, preserveAspectRatio: "xMidYMid slice" }) + el("rect", { class: "ky-pl-fb", x, y: cy - h / 2, width: w, height: h, rx: 0.25, fill: "none" });
@@ -211,7 +213,7 @@ export function raceArt(plan, o) {
211
213
  name: show.names ? Math.min(nameMax, Math.max(14, longest)) : 0,
212
214
  abbr: show.names ? Math.max(0, ...race.rows.map((r) => tw(r.abbr, SMALL))) : 0,
213
215
  seed: show.seeds && race.rows.some((r) => r.seed !== undefined) ? Math.max(...race.rows.map((r) => tw(r.seed ?? "", SMALL * 0.9))) : 0,
214
- flag: show.flags && race.rows.some((r) => safeLogo(r.flag) !== undefined) ? 4.5 : 0,
216
+ flag: show.flags && race.rows.some((r) => flagOf(r) !== undefined) ? 4.5 : 0,
215
217
  };
216
218
  let left = "";
217
219
  let reachLeft = 0;
@@ -18,6 +18,8 @@ export interface RaceRow {
18
18
  name: string;
19
19
  abbr: string;
20
20
  flag: string | undefined;
21
+ /** The country code of the flag, when the swimmer has one and no `flag` of its own. */
22
+ country: string | undefined;
21
23
  color: string | undefined;
22
24
  seed: string | undefined;
23
25
  /** The final time in seconds and as it is written (a time of text that cannot be read is written as it is). */
package/dist/pool.race.js CHANGED
@@ -66,6 +66,7 @@ export function racePlan(race, lanes, defaults) {
66
66
  name: clean(swimmer.name, 40) ?? "",
67
67
  abbr: (clean(swimmer.abbr, 5) ?? "").toLocaleUpperCase("en"),
68
68
  flag: typeof swimmer.flag === "string" ? swimmer.flag : undefined,
69
+ country: typeof swimmer.country === "string" ? swimmer.country : undefined,
69
70
  color: typeof swimmer.color === "string" ? swimmer.color : undefined,
70
71
  seed: typeof swimmer.seed === "number" ? (Number.isFinite(swimmer.seed) ? formatTime(swimmer.seed) : undefined) : clean(swimmer.seed, 12),
71
72
  time,
@@ -23,6 +23,8 @@ export interface Swimmer {
23
23
  abbr?: string;
24
24
  /** The flag or crest, drawn small beside the name. */
25
25
  flag?: string;
26
+ /** A country code (`CA`, `jp`) for the flag, drawn by the renderer of flags plugged in with `useFlags` (or the drawing's `flags` option), in its own proportions, where `flag` is missing. */
27
+ country?: string;
26
28
  /** The swimmer's colour (a cap, a club), drawn as a stripe on the label. */
27
29
  color?: string;
28
30
  /** The entry time. */
package/dist/react.d.ts CHANGED
@@ -9,7 +9,7 @@ export declare function kyogijoHtml(options: SurfaceOptions | ScoreOptions): {
9
9
  * @example
10
10
  * ```ts
11
11
  * import { kyogijoProps } from "@johnmorrisdotca/kyogijo-stadiums/react";
12
- * const props = kyogijoProps({ sport: "nba", away: { name: "Harbour City Gulls", score: 108 }, home: { name: "Prairie Ridge Bison", score: 112 }, status: "final" });
12
+ * const props = kyogijoProps({ sport: "nba", away: { name: "Australia", score: 108 }, home: { name: "Japan", score: 112 }, status: "final" });
13
13
  * console.log(props["data-kyogijo"], props.dangerouslySetInnerHTML.__html.startsWith("<svg"));
14
14
  * // nba true
15
15
  * ```
package/dist/react.js CHANGED
@@ -10,7 +10,7 @@ export function kyogijoHtml(options) {
10
10
  * @example
11
11
  * ```ts
12
12
  * import { kyogijoProps } from "@johnmorrisdotca/kyogijo-stadiums/react";
13
- * const props = kyogijoProps({ sport: "nba", away: { name: "Harbour City Gulls", score: 108 }, home: { name: "Prairie Ridge Bison", score: 112 }, status: "final" });
13
+ * const props = kyogijoProps({ sport: "nba", away: { name: "Australia", score: 108 }, home: { name: "Japan", score: 112 }, status: "final" });
14
14
  * console.log(props["data-kyogijo"], props.dangerouslySetInnerHTML.__html.startsWith("<svg"));
15
15
  * // nba true
16
16
  * ```
@@ -1,7 +1,7 @@
1
1
  // The lineup layer: a team's players placed by position code on the surface, each as a disc or a jersey with the shirt number in it and the name under it, with a captain's
2
2
  // armband and a small flag where they are given. It reads where each position stands from a formation (formations.ts, formations.sports.ts) and so needs no coordinates; two
3
3
  // teams are two layers. Written for this package.
4
- import { safeLogo } from "./logo.js";
4
+ import { flagPicture, safeLogo } from "./logo.js";
5
5
  import { esc, num } from "./format.js";
6
6
  import { FRAMES } from "./frames.js";
7
7
  import { positionName } from "./formations.js";
@@ -151,7 +151,7 @@ export function drawLineup(layer, env) {
151
151
  badges.push(titled("circle", ` class="ky-lc" cx="${num(bx)}" cy="${num(by)}" r="${num(r)}"`, words.captainTip));
152
152
  text.push(`<text class="ky-cl" style="font-size:${num(r * 1.25)}px" x="${num(bx)}" y="${num(by + r * 0.45)}"${env.turned ? ` transform="rotate(-90 ${num(bx)} ${num(by)})"` : ""}>${esc(words.captainMark)}</text>`);
153
153
  }
154
- const flag = safeLogo(player?.flag);
154
+ const flag = safeLogo(player?.flag) ?? flagPicture(player?.country, "rect", 24);
155
155
  if (flag !== undefined) {
156
156
  const h = size * 0.3;
157
157
  const w = h * 1.5;
@@ -198,6 +198,8 @@ export interface LineupPlayer extends MarkDatum {
198
198
  number?: string | number;
199
199
  /** A flag or crest for a small badge on the mark: an SVG as text, an image `data:` address or a path or address of an image. The package draws no flag of its own. */
200
200
  flag?: string;
201
+ /** A country code (`CA`, `jp`) for the badge, drawn by the renderer of flags plugged in with `useFlags` (or the drawing's `flags` option), in its own proportions, where `flag` is missing. */
202
+ country?: string;
201
203
  /** The captain wears an armband: a small "C" on the mark. */
202
204
  captain?: boolean;
203
205
  /** 1 by default. Hockey's second line is `line: 2` with the same codes. */
@@ -40,7 +40,7 @@ export declare function turnSupported(win?: {
40
40
  * @example
41
41
  * ```ts no-run
42
42
  * import { mountKyogijoTurn } from "@johnmorrisdotca/kyogijo-stadiums/turn";
43
- * const view = mountKyogijoTurn(document.querySelector("#court")!, { sport: "volleyball", home: { name: "Harbour City Gulls", score: 3 }, away: { name: "Prairie Ridge Bison", score: 2 } }, { preset: "end" });
43
+ * const view = mountKyogijoTurn(document.querySelector("#court")!, { sport: "volleyball", home: { name: "Japan", score: 3 }, away: { name: "USA", score: 2 } }, { preset: "end" });
44
44
  * view.preset("corner");
45
45
  * view.set({ yaw: 60, pitch: 40 });
46
46
  * ```
package/dist/turn.dom.js CHANGED
@@ -24,7 +24,7 @@ const between = (from, to, t) => ({ yaw: from.yaw + (nearest(from.yaw, to.yaw) -
24
24
  * @example
25
25
  * ```ts no-run
26
26
  * import { mountKyogijoTurn } from "@johnmorrisdotca/kyogijo-stadiums/turn";
27
- * const view = mountKyogijoTurn(document.querySelector("#court")!, { sport: "volleyball", home: { name: "Harbour City Gulls", score: 3 }, away: { name: "Prairie Ridge Bison", score: 2 } }, { preset: "end" });
27
+ * const view = mountKyogijoTurn(document.querySelector("#court")!, { sport: "volleyball", home: { name: "Japan", score: 3 }, away: { name: "USA", score: 2 } }, { preset: "end" });
28
28
  * view.preset("corner");
29
29
  * view.set({ yaw: 60, pitch: 40 });
30
30
  * ```
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Background } from "./background.ts";
2
2
  import type { EmblemRef, EmblemRenderer } from "./emblems-source.ts";
3
+ import type { FlagRenderer } from "./flags-source.ts";
3
4
  import type { Layer } from "./layers.types.ts";
4
5
  import type { Unit } from "./units.ts";
5
6
  import type { SoccerFrame, SoccerProviderId } from "./surfaces/soccer-providers.ts";
@@ -478,12 +479,17 @@ export interface PageantOptions {
478
479
  }
479
480
  /** One team of a score. */
480
481
  export interface Team {
481
- /** The name, as it is to be written: "Harbour City Gulls". */
482
+ /** The name, as it is to be written: "Canada". */
482
483
  name: string;
483
484
  /** A short form, three letters or so, for the score and the badge. Taken from the name when missing. */
484
485
  abbr?: string;
485
486
  /** The score. A number, or text such as "–" before the game. */
486
487
  score?: number | string;
488
+ /**
489
+ * A country code (`CA`, `jp`, `GB-ENG`) for the team's flag, drawn by the renderer of flags plugged in with `useFlags` (or the drawing's `flags` option): round in a round mark, in its own proportions on a
490
+ * plain mark, a carpet and a banner, round on a stage. It wins over `logo` where the renderer has a flag for the code. With no renderer, or none for the code, the `logo` is drawn, or the initials.
491
+ */
492
+ flag?: string;
487
493
  /** The logo: an `https:` or relative address, an image `data:` address, an SVG document as text, or, with a renderer of emblems plugged in (`useEmblems`), the id of a ready-made emblem: `"crest:shield"` takes the team's `color`, `textColor` and `abbr`. */
488
494
  logo?: EmblemRef;
489
495
  /**
@@ -568,6 +574,11 @@ export interface SurfaceOptions {
568
574
  id?: string;
569
575
  /** A renderer of ready-made emblems for this drawing alone, so that a `logo`, an `emblem` or a mark may be an emblem's id: `emblems: renderEmblem` from `@johnmorrisdotca/dougu-sports/emblems`. Over the one the page plugged in with `useEmblems`. */
570
576
  emblems?: EmblemRenderer;
577
+ /**
578
+ * A renderer of country flags for this drawing alone, so that a team's `flag` code is drawn: a synchronous function from a code and `{ shape, size, theme }` to an SVG string, such as a lookup of flags
579
+ * loaded from `@johnmorrisdotca/hata` first. Over the one the page plugged in with `useFlags`. See `docs/flags.md`.
580
+ */
581
+ flags?: FlagRenderer;
571
582
  /** The ground to draw round the playing surface, in `units` (feet by default). A default for each sport. */
572
583
  margin?: number;
573
584
  /**
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** The package's version: the same as package.json's, and a test holds them to each other. */
2
- export declare const VERSION = "0.8.0";
2
+ export declare const VERSION = "0.10.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** The package's version: the same as package.json's, and a test holds them to each other. */
2
- export const VERSION = "0.8.0";
2
+ export const VERSION = "0.10.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johnmorrisdotca/kyogijo-stadiums",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Kyogijo Stadiums 競技場, 39 sports' surfaces as SVG, drawn to scale from the rulebooks: NFL, CFL and IFAF football fields, an NHL rink, an NBA court, MLB ballparks, soccer pitches, curling sheets, athletics stadiums, speed skating, short track and figure skating rinks, swimming pools, water polo fields, diving wells, artistic swimming areas, and the courts and fields of tennis, volleyball (indoor, beach and sitting), badminton, pickleball, table tennis, padel, squash, racquetball, sepak takraw, teqball, roundnet, netball, lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, and the budo of judo, karate, kendo, sumo and kyudo with a dojo of tatami laid as real units, with each team's name and logo on its side and the score in the middle, stands and a crowd, a pageant of flags, and a 3D view. Light and dark, accessible, a compact badge for lists, a helper for React and a custom element. Zero dependencies.",
5
5
  "keywords": [
6
6
  "sports",
@@ -238,9 +238,13 @@
238
238
  "node": ">=22"
239
239
  },
240
240
  "peerDependencies": {
241
+ "@johnmorrisdotca/hata": ">=1.5.0 <2",
241
242
  "@resvg/resvg-js": ">=2.6.0"
242
243
  },
243
244
  "peerDependenciesMeta": {
245
+ "@johnmorrisdotca/hata": {
246
+ "optional": true
247
+ },
244
248
  "@resvg/resvg-js": {
245
249
  "optional": true
246
250
  }
@@ -275,6 +279,7 @@
275
279
  "@eslint/js": "^9.0.0",
276
280
  "@johnmorrisdotca/chizu": "1.4.0",
277
281
  "@johnmorrisdotca/dougu-sports": "0.2.0",
282
+ "@johnmorrisdotca/hata": "1.5.0",
278
283
  "@playwright/test": "^1.63.0",
279
284
  "eslint": "^9.0.0",
280
285
  "marked": "^18.1.1",