@johnmorrisdotca/kyogijo-stadiums 0.18.0 → 0.19.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 +29 -0
- package/README.md +35 -21
- package/dist/common.d.ts +5 -0
- package/dist/common.js +6 -1
- package/dist/judging-entry.d.ts +6 -1
- package/dist/judging-entry.js +5 -1
- package/dist/judging.board.d.ts +26 -0
- package/dist/judging.board.js +125 -0
- package/dist/judging.broadcast.d.ts +6 -0
- package/dist/judging.broadcast.js +72 -0
- package/dist/judging.d.ts +7 -0
- package/dist/judging.draw.d.ts +19 -6
- package/dist/judging.draw.js +16 -104
- package/dist/judging.js +17 -2
- package/dist/judging.mount.d.ts +16 -0
- package/dist/judging.mount.js +69 -0
- package/dist/judging.plan.d.ts +52 -0
- package/dist/judging.plan.js +91 -0
- package/dist/judging.print.d.ts +58 -0
- package/dist/judging.print.js +86 -0
- package/dist/judging.style.d.ts +5 -0
- package/dist/judging.style.js +22 -0
- package/dist/judging.text.d.ts +7 -0
- package/dist/judging.text.js +23 -0
- package/dist/judging.turn.js +8 -8
- package/dist/judging.types.d.ts +14 -0
- package/dist/judging.words.d.ts +2 -0
- package/dist/judging.words.js +4 -2
- package/dist/surfaces/budo.d.ts +2 -0
- package/dist/surfaces/budo.js +17 -1
- package/dist/turn.kit.d.ts +6 -1
- package/dist/turn.kit.js +6 -2
- package/dist/turn.markup.js +1 -1
- package/dist/turn.model.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,35 @@ All notable changes to this project are written here. The format follows
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.19.0] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **A broadcast view of a judging assignment** (`view: "broadcast"`). The mat large and prominent as a television would show it, 16:9, with the officials superimposed on a board at its side: the package's own score panel drawn for officials (the same dark rounded plate, the mat's name where a score panel has the competition, column heads, a row for each seat with its number on the round badge the seats wear, the name on a coloured chip, the ID where a score would be, and the style at the foot). The board lies beside the contest area and never over it (a test holds the board clear of the mat's picture and of the middle of the contest area for kata and shiai, a bench close up, six long names, and every width), the seat badges stay on the seats, and the whole picture scales evenly: no text is stretched (a test: every font size is in proportion at twice the width). A mat takes a `line` (`Round 2`, `Pool B`, at most 60 characters) shown before the style at the board's foot. `drawJudging` draws it in 2D; `mountJudgingBroadcast` mounts the 3D view from the Broadcast camera with the board laid over it (a share of the view's width so it scales with it, under the view where that is narrower than 640 px, and never taking the pointer); `judgingBoard` is the board alone for a page of your own. Light and dark, English and Japanese. The demo opens it with `?view=broadcast` (3D) or `?view=broadcast&dim=2d`.
|
|
15
|
+
- **Printing the plan-and-chart layout** (`judgingPrint`, `judgingPrintSheets`, `judgingPrintStyle`, `JUDGING_PAPER`). One mat to a page on A4 or US letter, portrait or landscape, in the light colours, the picture scaled evenly to the page and anchored at its top; `judgingPrint` is a whole HTML document that opens as the pages on a grey desk and prints as they are (Save as PDF for a file). The demo has a "Print or save as PDF" button with a choice of paper (`?paper=letter`).
|
|
16
|
+
- `JudgingDrawing.boards` (where each mat's board, the part of the mat shown and the middle of the contest area are), `matLine`, `KYOGIJO_JUDGING_BOARD_STYLE`, `KYOGIJO_JUDGING_BROADCAST_STYLE`, `BOARD_BASE`, `BROADCAST_RATIO`, `boardFoot`.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **A box with the picture's words no longer pops up over the mat.** A `<title>` that is a direct child of the root `<svg>` is the browser's tooltip for the whole drawing, so resting the pointer on the 2D plan showed "Judging assignments: Kata, 5 judges, 2 mats" in a box on top of the mat, and on a score on a surface "Mexico 11, USA 10, Final" over its top left. A judging picture now keeps its title and description in a `<defs>` (the picture is still named by them: `aria-labelledby` points at them), and the demo's pages move the title of every drawing they show into a `<defs>` the same way (`demo/quiet.js`); a surface's own markup is unchanged byte for byte, so a page that wants no tooltip does the same with its drawings.
|
|
21
|
+
|
|
22
|
+
- **Chart lines stay inside their rows in a wide face.** The chart's name and ID lines were fitted to an estimate of the face's width, and in a wider face (Verdana on Windows, DejaVu Sans on Linux, where the demo's browser test of 0.18.1 failed) the last words of a long name crossed the row's right edge by a few pixels. The chart now fits its lines to 94 % of the room, and a browser test sets the board and the chart in Verdana and DejaVu Sans.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- The plan view of a judging assignment moved its title and description into a `<defs>` (see above); everything else it draws is as it was. The plan's drawing code is in `judging.plan.ts` and the words in `judging.text.ts`, shared by both views.
|
|
27
|
+
|
|
28
|
+
## [0.18.1] - 2026-10-20
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **The seats show their number, and the names are in the chart.** By default every seat of a judging assignment is a large round numbered badge (the chart's own), in 2D and in 3D, and the chart beside it is the key (`chart: "auto"` now always draws it, unless `seatNames` is on and every name fits). Putting the names on the seats is the new option `seatNames: true` (off by default), which sets them in the chart's own face and weight, scaled evenly, in the biggest size that fits and never below a readable floor, and falls back to the number alone when a name does not fit. The demo has a "Names on the seats too" box (`seatnames=1`).
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **Nothing is squeezed or stretched in a judging picture.** The 3D badges, cards and the mat's sign stood upright, so a tipped view foreshortened them and their type looked squeezed: they now lean back to face the eye squarely (`Plane.lean`, turned and never stretched), at every viewpoint. A test measures each one's shape on the screen against its own, and that no text anywhere has `textLength`, `lengthAdjust` or a two-number `scale`.
|
|
37
|
+
- **The tapes of a judo area were hairlines.** The kata area's centre and starting tapes (5 cm by 50 cm) and a contest area's two start tapes, and the sumo's shikiri-sen, are drawn at least 0.75 % of the plan's width across (10.5 cm on a kata area's 14 m, about 4 pixels on a plan 560 pixels across) unless `exactLines: true`, which draws the rule's 5 cm. The floor is a readability aid, not a measurement: a tape's length is always the rule's, and it is widened about its middle. In 3D (the same floor) and in tournament layouts too.
|
|
38
|
+
|
|
10
39
|
## [0.18.0] - 2026-10-20
|
|
11
40
|
|
|
12
41
|
### Added
|
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
|
|
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, the language chooser and links, and an NHL rink drawn wide on an ice-blue background with a made-up game on it, the USA on the left, Canada on the right and the score 3 to 2, Final/OT, in the middle. The controls on the right list the sports, 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
|
|
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 and controls, and under them, on a background of floodlight beams, a football field standing tall, Mexico's green end zone at the top and the USA's navy one at the bottom, each with its flag and name, 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>
|
|
@@ -65,27 +65,27 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
65
65
|
|
|
66
66
|
## Who it is for
|
|
67
67
|
|
|
68
|
-
- **A results page or a stats site** that has
|
|
68
|
+
- **A results page or a stats site** that has a game's score and wants a picture of where it was played.
|
|
69
69
|
- **A list of games** that needs a compact strip for each, small enough for a phone.
|
|
70
|
-
- **Anyone drawing a rink,
|
|
70
|
+
- **Anyone drawing a rink, field, court or ballpark** for a poster or a lesson, with the dimensions right and the colours their own.
|
|
71
71
|
- **A site that uses a framework or none**: the drawing is a string, so it works from a server, a build step, a framework, a custom element or a frame.
|
|
72
72
|
|
|
73
73
|
## Features
|
|
74
74
|
|
|
75
|
-
- **Thirty-nine surfaces, to scale.** The NFL, CFL and IFAF fields, the NHL rink, the NBA court, the soccer pitch and futsal court, the baseball field, the curling sheet,
|
|
75
|
+
- **Thirty-nine surfaces, to scale.** The NFL, CFL and IFAF fields, the NHL rink, the NBA court, the soccer pitch and futsal court, the baseball field, the curling sheet, twelve net and racket sports, the pools, the athletics stadium, the skating rinks, seven field sports and the budō. Every figure is cited in [sources](./docs/sources.md). [The surfaces](./docs/surfaces.md).
|
|
76
76
|
- **Each league's rulebook.** `league: "fiba"` draws a court as FIBA marks it: 48 variants, from the WNBA, the NCAA and the IIHF to Little League, PONY, softball, Curling Canada, FIVB's beach volleyball, rugby league and the NLL's box lacrosse, each cited. [League variants](./docs/variants.md).
|
|
77
77
|
- **A realistic basketball floor.** `court: { hardwood: true }` draws maple boards that run the length of the court with staggered ends, grain, stained keys, the baskets and stanchions with soft shadows, a coaching box and benches, and a satin sheen, in every league and renderer. The clean floor stays the default. [Hardwood](./docs/hardwood.md).
|
|
78
78
|
- **The stands and the crowd.** `crowd: true` draws the seating round any surface that has spectators: a bowl, two sides, a horseshoe, courtside rows or a ballpark's grandstands, with the people as seeded heads and shoulders in the home colours and the empty seats showing (`density`, or `attendance` over `capacity`). [The crowd](./docs/crowd.md).
|
|
79
79
|
- **Curling, from the rule books.** A sheet from World Curling's and Curling Canada's rules, tall by default, with the board and the hammer in a score, `curlingStones` for the stones of an end, scored by the rules, `show: "folded"` for the whole sheet with both houses enlarged beside it, and a heat map and statistics for many ends. [Curling](./docs/curling.md).
|
|
80
80
|
- **Net, racket and court sports, from their rulebooks.** The ITF's, FIVB's (indoor, beach, sitting), BWF's, USA Pickleball's and ITTF's courts and table, the padel, squash, racquetball, sepak takraw, teqball, roundnet and netball courts, each in its look (hard court, clay, grass, wood, sand), with a board of sets and games. [Net, racket and court sports](./docs/courts.md).
|
|
81
|
-
- **Swimming, water polo, diving and artistic swimming, from World Aquatics' regulations.** The
|
|
81
|
+
- **Swimming, water polo, diving and artistic swimming, from World Aquatics' regulations.** The 50 or 25 m pool with its lanes, ropes, blocks and touch panels; the water polo field; the diving well; the artistic swimming area; several pools in a natatorium. A race's lanes carry names, flags, places, times and splits, with a replay and a `splitsChart`. [Pools](./docs/pools.md).
|
|
82
82
|
- **Lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, from their rulebooks.** The fields and floors of World Lacrosse, World Rugby, the NRL, the AFL, the GAA, the FIH and the IHF, and a cricket ground with a boundary of your own. A score is goals and behinds, goals and points or a board of runs, wickets and overs. [Field sports](./docs/field-sports.md).
|
|
83
83
|
- **The athletics stadium, from World Athletics' rules.** The 400 m track with its lanes and staggers worked out from the running lines, curved and relay starts, hurdles, the steeplechase, every field event, a close-up of each start, the covered 200 m track, and lane draws, results, a race replay and the marks of throws and jumps. [The athletics stadium](./docs/athletics.md).
|
|
84
84
|
- **The skating rinks, from the ISU's rules.** The 400 m speed skating track with its lanes, blocks and the lines of every race worked out lane by lane; the short track's oval; the figure skating rink of 60 by 30 m with its judges' seats; and pairs, results, a race replay and the elements of a programme on the ice. [The skating rinks](./docs/skating.md).
|
|
85
|
-
- **The budō, from the federations' rules.** The IJF's and the All Japan Judo Federation's judo areas, the WKF's karate areas, the kendo shiai-jo, the sumo dohyō, the kyūdōjō, and **a dojo builder**: a floor of tatami laid as real units, in jō or metres, with its walls, doors, windows and shrine.
|
|
85
|
+
- **The budō, from the federations' rules.** The IJF's and the All Japan Judo Federation's judo areas, the WKF's karate areas, the kendo shiai-jo, the sumo dohyō, the kyūdōjō, and **a dojo builder**: a floor of tatami laid as real units, in jō or metres, with its walls, doors, windows and shrine. Scores are judo's ippon, waza-ari and shido, karate's and kendo's points and sumo's kimarite. [The budō](./docs/budo.md).
|
|
86
86
|
- **Soccer, to the Laws.** A pitch from Law 1 of the IFAB Laws of the Game of any size, with presets (international, UEFA, MLS, NCAA, the FA's 9-, 7- and 5-a-side, FIFA's futsal), half pitches, five mowing patterns, four goal styles, penalties and extra time in a score. [Soccer](./docs/soccer.md).
|
|
87
87
|
- **Every ballpark.** The 30 current MLB parks and 44 that MLB clubs have left, and the 12 home parks of Nippon Professional Baseball with eight other NPB grounds, each with its fence drawn from the distances published for it, as it stood in a season. [Ballparks](./docs/ballparks.md).
|
|
88
|
-
- **Soccer grounds, arenas and an atlas.** 64 soccer grounds
|
|
88
|
+
- **Soccer grounds, arenas and an atlas.** 64 soccer grounds at their published sizes, 167 NHL, NBA, WNBA and PWHL arenas (`drawKyogijo({ sport: "nhl", arena: "boston-garden" })`), and every park, ground, arena and budō hall (330 places) on a map, found by any of its names. [The grounds](./docs/grounds.md), [the arenas](./docs/arenas.md), [the atlas](./docs/atlas.md), [names](./docs/ballparks.md#names).
|
|
89
89
|
- **Walls and quirks.** How high the fence stands, stretch by stretch and season by season (the Green Monster at 37 feet 2 inches), drawn as a band outside the fence whose width and shade say the height, with a key (`walls`); and Tal's Hill, Wrigley Field's ivy and basket, poles, bullpens and dugouts (`quirks`), each from the park's article, none guessed: [ballparks](./docs/ballparks.md).
|
|
90
90
|
- **Special games.** A surface set inside another, to scale: an NHL rink on a ballpark's infield or a football stadium's field, a college basketball court on the deck of a carrier, a baseball field laid over a London stadium's pitch. 18 games, each with its day, its venue and its sources. [Special games](./docs/special-games.md).
|
|
91
91
|
- **Surfaces through the years.** `year: 1975` draws a surface as its league's rules marked it that season, each change cited. [Surfaces through the years](./docs/eras.md).
|
|
@@ -104,7 +104,7 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
104
104
|
- **Tournament layouts.** Several surfaces laid out together for one large event, to scale, on one floor, as one SVG: thirteen presets from table tennis, pickleball, curling, judo, karate, badminton and tennis, each with its rule and sources, whether it fits a hall, and a real stadium round it. [Tournament layouts](./docs/multi.md).
|
|
105
105
|
- **Judging assignments.** Who judges where. [Judging](./docs/judging.md).
|
|
106
106
|
- **Replay.** Tracking data played on any surface: the players with their numbers, the ball and its trail, and the passes, shots and goals as they happen, with controls, the keyboard and a live region, steps for a reader who prefers reduced motion, and a pause when the page is hidden. [Replay](./docs/replay.md).
|
|
107
|
-
- **A 3D view.** Any surface as a floor that turns by mouse, touch, wheel or keys, with four viewpoints (overhead, broadcast, end-on, low corner), and what the rulebook stands on it at its height (nets, baskets, rink boards and glass, goals, a ballpark's fence,
|
|
107
|
+
- **A 3D view.** Any surface as a floor that turns by mouse, touch, wheel or keys, with four viewpoints (overhead, broadcast, end-on, low corner), and what the rulebook stands on it at its height (nets, baskets, rink boards and glass, goals, a ballpark's fence, a pool's blocks, a table tennis area's surrounds) and the venue round it (raked stands, roofs, a dojo's walls). Plain DOM and CSS. [The 3D view](./docs/turn.md).
|
|
108
108
|
- **Renderers.** The same drawing as plain data (a scene), on a canvas (a browser's or a Node canvas), in a d3 selection, as a mark of an Observable Plot, as GeoJSON and as a PNG in Node, each an entry of its own that imports nothing from outside the package. [Renderers](./docs/renderers.md).
|
|
109
109
|
- **Units and frames.** Each surface in its rulebook's unit and any other, and 48 coordinate frames (ten soccer providers, the NHL API, HockeyTech, NBA stats, NFL tracking, MLBAM, Retrosheet, and a place from the net, the centre or the middle of the water of each other surface) to move a provider's points onto a surface. [Units](./docs/units.md), [coordinate frames](./docs/frames.md).
|
|
110
110
|
- **A compact badge and a compact card.** One strip for a list, or the surface with that strip under it.
|
|
@@ -132,7 +132,7 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
132
132
|
| `./turn` | A surface as a 3D view that turns, with the net, basket, goal or posts standing on it. |
|
|
133
133
|
| `./scene`, `./canvas`, `./d3`, `./plot`, `./geojson`, `./png` | The drawing as data; on a canvas; in a d3 selection; as an Observable Plot mark; as GeoJSON; as a PNG (the optional peer `@resvg/resvg-js`). |
|
|
134
134
|
| `./multi` | `drawMulti`, `multiFit`: several surfaces laid out for one event, in a hall ([docs](./docs/multi.md), [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html)). |
|
|
135
|
-
| `./judging` | `drawJudging`: who judges where ([docs](./docs/judging.md)). |
|
|
135
|
+
| `./judging` | `drawJudging`, `judgingBoard`, `mountJudgingBroadcast`, `judgingPrint`: who judges where, as a plan, on a broadcast board or on paper ([docs](./docs/judging.md)). |
|
|
136
136
|
| `./layouts` | `drawGrid` and `GRID_PRESETS`: small multiples with a title, a subtitle, a key and a credit line; the grounds behind a drawing or a grid. |
|
|
137
137
|
| `./mount`, `./react`, `./element`, `./element/define` | Draw into a container; React props; the `<kyogijo-field>` element and its registration. |
|
|
138
138
|
|
|
@@ -183,7 +183,7 @@ console.log(svg.includes("Cup Final, Game 7"), svg.includes("Final/OT"));
|
|
|
183
183
|
<p align="center">
|
|
184
184
|
<picture>
|
|
185
185
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/football-desk-dark.webp">
|
|
186
|
-
<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
|
|
186
|
+
<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 name, the USA's navy one on the right, the yard lines and numbers between them, and the score panel at midfield reading 27 to 24, Final, Championship Game." width="720">
|
|
187
187
|
</picture>
|
|
188
188
|
<br><em>A football field: the end zones in the teams' colours, the score at midfield.</em>
|
|
189
189
|
</p>
|
|
@@ -228,7 +228,7 @@ console.log(box(wide), box(tall));
|
|
|
228
228
|
<p align="center">
|
|
229
229
|
<picture>
|
|
230
230
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/tall-phone-dark.webp">
|
|
231
|
-
<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
|
|
231
|
+
<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 ice blue: the USA's flag and name in the upper zone, Canada's in the lower, each upright, the score panel between them." width="240">
|
|
232
232
|
</picture>
|
|
233
233
|
<br><em>The same game tall: the teams top and bottom, every word upright.</em>
|
|
234
234
|
</p>
|
|
@@ -263,7 +263,7 @@ console.log(svg.includes("甲子園球場のグラウンド"), svg.includes("阪
|
|
|
263
263
|
<p align="center">
|
|
264
264
|
<picture>
|
|
265
265
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/ballpark-desk-dark.webp">
|
|
266
|
-
<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
|
|
266
|
+
<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: the outfield fence at its published distances, 95 metres at the lines and 118 in the alleys, the infield dirt, and a red and a navy dugout panel with Japan's and the USA's flags." width="640">
|
|
267
267
|
</picture>
|
|
268
268
|
<br><em>A ballpark's fence, drawn through the distances its article publishes.</em>
|
|
269
269
|
</p>
|
|
@@ -368,7 +368,7 @@ console.log(items.map((item) => item.kind).join(), html.includes("preserve-3d"))
|
|
|
368
368
|
// net,netposts,antennae false
|
|
369
369
|
```
|
|
370
370
|
|
|
371
|
-
The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewpoints, with what the rulebook stands on it at its height; each part is
|
|
371
|
+
The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewpoints, with what the rulebook stands on it at its height; each part is one `matrix3d`, so there is no 3D context for a phone to lose. In the element: `<kyogijo-field sport="nhl" turn turn-view="broadcast">`. [The 3D view](./docs/turn.md).
|
|
372
372
|
|
|
373
373
|
<p align="center">
|
|
374
374
|
<picture>
|
|
@@ -496,7 +496,7 @@ console.log(svg.includes('viewBox="0 0 1200 675"'), svg.includes("Three ballpark
|
|
|
496
496
|
|
|
497
497
|
### Several surfaces on one floor
|
|
498
498
|
|
|
499
|
-
`drawMulti` lays the package's own surfaces out together for one large event, to scale, on one floor, with the officials' chairs and boards, and places for the event's words and marks (`sample: true` fills them with an invented event; [tournament layouts](./docs/multi.md)). Thirteen presets
|
|
499
|
+
`drawMulti` lays the package's own surfaces out together for one large event, to scale, on one floor, with the officials' chairs and boards, and places for the event's words and marks (`sample: true` fills them with an invented event; [tournament layouts](./docs/multi.md)). Thirteen presets; `multiFit` says whether a layout fits a hall, `stadium: true` sets it inside real stands, and `mountMultiTurn` turns it in 3D.
|
|
500
500
|
|
|
501
501
|
```ts
|
|
502
502
|
import { drawMulti, multiLayout } from "@johnmorrisdotca/kyogijo-stadiums/multi";
|
|
@@ -550,11 +550,28 @@ The [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html) turns
|
|
|
550
550
|
<p align="center">
|
|
551
551
|
<picture>
|
|
552
552
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-3d-desk-dark.webp">
|
|
553
|
-
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-3d-desk-light.webp" alt="A kata area's judges' table in 3D,
|
|
553
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-3d-desk-light.webp" alt="A kata area's judges' table in 3D, numbered badges, and the chart." width="640">
|
|
554
554
|
</picture>
|
|
555
|
-
<br><em>Judges in 3D.</em>
|
|
555
|
+
<br><em>Judges, in 3D.</em>
|
|
556
556
|
</p>
|
|
557
557
|
|
|
558
|
+
The broadcast view puts the mat large, with the officials on a board at its side; `judgingPrint` prints one mat to an A4 or US letter page.
|
|
559
|
+
|
|
560
|
+
<p align="center">
|
|
561
|
+
<picture>
|
|
562
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-broadcast-3d-desk-dark.webp">
|
|
563
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-broadcast-3d-desk-light.webp" alt="A kata mat in 3D from the Broadcast camera, with a dark board at its side listing each judge's number, name and ID." width="640">
|
|
564
|
+
</picture>
|
|
565
|
+
<br><em>The broadcast view.</em>
|
|
566
|
+
</p>
|
|
567
|
+
|
|
568
|
+
<p align="center">
|
|
569
|
+
<picture>
|
|
570
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-print-a4-desk-dark.webp">
|
|
571
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/judging-print-a4-desk-light.webp" alt="An A4 page with the plan of one kata mat and the chart of its five judges under it." width="640">
|
|
572
|
+
</picture>
|
|
573
|
+
<br><em>One mat to an A4 page.</em>
|
|
574
|
+
</p>
|
|
558
575
|
|
|
559
576
|
### A table tennis area
|
|
560
577
|
|
|
@@ -692,8 +709,7 @@ English and Japanese: the title, the description and the standard statuses of a
|
|
|
692
709
|
Not here yet, and each welcome as an [issue](https://github.com/johnmorrisdotca/kyogijo-stadiums/issues):
|
|
693
710
|
|
|
694
711
|
- **More surfaces**: the FIBA and college courts, the international rink, rugby pitches, a stadium's seating, soccer's beach and street formats.
|
|
695
|
-
- **
|
|
696
|
-
- **More parks of the past**: the grounds of the 19th century, and the parks whose articles give no distances yet (the Kingdome, Joe Robbie Stadium, the Los Angeles Coliseum), when they do.
|
|
712
|
+
- **More parks of the past**: the 19th-century grounds, and the parks whose articles give no distances yet (the Kingdome, Joe Robbie Stadium).
|
|
697
713
|
- **More charts on data layers**: a formation chart, a pass sonar chart and a Voronoi chart of their own (the layers exist; see [team shape](./docs/team-shape.md)).
|
|
698
714
|
- **Football in a different standard**: the college and high-school hash marks.
|
|
699
715
|
|
|
@@ -703,8 +719,6 @@ Left out on purpose: statistics, rosters and schedules. Kyogijo Stadiums draws t
|
|
|
703
719
|
|
|
704
720
|
The drawing is plain functions over plain data with no DOM and no dependency. The dimensions are in one file, the ballparks are generated from a reviewed list, and each surface is a function that returns its markup and the places the teams and the score go. Every entry point stands apart, so that importing the geometry, the parks or the grounds loads nothing else. The files and what each is for are in [architecture](./docs/architecture.md).
|
|
705
721
|
|
|
706
|
-
Tests sit beside the code. `scripts/` builds the demo and the docs site, checks the packed package and the README's examples, and takes the README's pictures; `demo/` is the page and the frame; `e2e/` plays the demo and the docs in a real browser.
|
|
707
|
-
|
|
708
722
|
## The name
|
|
709
723
|
|
|
710
724
|
*Kyogijo* (競技場, kyōgijō, きょうぎじょう) is Japanese for a sports ground: the place a contest is held. "Stadiums" is added in English, so that the name says what it draws; in Japanese the name stays 競技場. It is written with 競技, "contest" or "competition", and 場, "place", and said in five beats, *kyo-u-gi-jo-u*. In Japanese it is the general word for a place where sport is played, a stadium or a ground; the package uses it as a name for every surface it draws, the field, the rink, the court and the diamond. The long vowels are written without a macron in the package's name, as in the other packages of the family.
|
package/dist/common.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import type { SurfaceOptions } from "./types.ts";
|
|
|
2
2
|
import { type Unit } from "./units.ts";
|
|
3
3
|
/** Text made safe for a class name or an id: letters, digits, underscores, spaces and hyphens. */
|
|
4
4
|
export declare const safeClass: (text: string | undefined) => string;
|
|
5
|
+
/**
|
|
6
|
+
* The title and the description of a drawing, as the first thing in it: the accessible name (`aria-labelledby` points at them). They sit in a `<defs>` so that they are never a tooltip: a `<title>` that is a direct child of
|
|
7
|
+
* the root makes the browser pop a box with its words up wherever the pointer is over the drawing, which on a mat reads as a label drawn on top of it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const metaMarkup: (titleId: string, title: string, descId: string, description: string) => string;
|
|
5
10
|
/** The prefix of the ids inside a drawing: the `id` option, or a hash of the options, so that the same call gives the same drawing. */
|
|
6
11
|
export declare const drawingId: (o: SurfaceOptions) => string;
|
|
7
12
|
/** True when a drawing with these options lies in portrait. */
|
package/dist/common.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
// What the drawing and the data layers both need: the drawing's id, whether it lies tall, and the unit its lengths are in.
|
|
2
2
|
// Kept apart from draw.ts so that layers.ts need not import the file that imports it.
|
|
3
|
-
import { hash } from "./format.js";
|
|
3
|
+
import { esc, hash } from "./format.js";
|
|
4
4
|
import { convertLength, isUnit } from "./units.js";
|
|
5
5
|
import { VERSION } from "./version.js";
|
|
6
6
|
/** Text made safe for a class name or an id: letters, digits, underscores, spaces and hyphens. */
|
|
7
7
|
export const safeClass = (text) => (text ?? "").replace(/[^\w -]/g, "").trim();
|
|
8
|
+
/**
|
|
9
|
+
* The title and the description of a drawing, as the first thing in it: the accessible name (`aria-labelledby` points at them). They sit in a `<defs>` so that they are never a tooltip: a `<title>` that is a direct child of
|
|
10
|
+
* the root makes the browser pop a box with its words up wherever the pointer is over the drawing, which on a mat reads as a label drawn on top of it.
|
|
11
|
+
*/
|
|
12
|
+
export const metaMarkup = (titleId, title, descId, description) => `<defs><title id="${titleId}">${esc(title)}</title><desc id="${descId}">${esc(description)}</desc></defs>`;
|
|
8
13
|
/** The prefix of the ids inside a drawing: the `id` option, or a hash of the options, so that the same call gives the same drawing. */
|
|
9
14
|
export const drawingId = (o) => safeClass(o.id).replace(/ /g, "-") || `ky-${hash(JSON.stringify([o, VERSION]))}`;
|
|
10
15
|
/** True when a drawing with these options lies in portrait. */
|
package/dist/judging-entry.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
export { judgingBoard, boardFoot, BOARD_BASE } from "./judging.board.ts";
|
|
2
|
+
export { JUDGING_PAPER, judgingPrint, judgingPrintSheets, judgingPrintStyle } from "./judging.print.ts";
|
|
3
|
+
export type { JudgingPrintOptions } from "./judging.print.ts";
|
|
4
|
+
export { KYOGIJO_JUDGING_BROADCAST_STYLE, mountJudgingBroadcast } from "./judging.mount.ts";
|
|
5
|
+
export { BROADCAST_RATIO } from "./judging.broadcast.ts";
|
|
1
6
|
export { drawJudging, judgingChart, judgingDrawing, judgingTable, judgingText } from "./judging.draw.ts";
|
|
2
7
|
export { JUDGING_HEIGHTS, JUDGING_PRESETS, buildJudgingTurn, judgingTurnMarkup, mountJudgingTurn } from "./judging.turn.ts";
|
|
3
8
|
export { JUDGING_LEAGUE, JUDGING_MATS_MAX, JUDGING_SEATS, JUDGING_SEAT_COUNT, JUDGING_SEAT_WORDS, JUDGING_STYLES } from "./judging.data.ts";
|
|
4
9
|
export { JUDGING_LIMITS, benchOf, judgingPlan, judgingSetting, matLabel, seatIn, seatOf, seatsOf } from "./judging.ts";
|
|
5
10
|
export { fitCard, fitChart, fitSeats, wrapText } from "./judging.fit.ts";
|
|
6
|
-
export { KYOGIJO_JUDGING_STYLE } from "./judging.style.ts";
|
|
11
|
+
export { KYOGIJO_JUDGING_BOARD_STYLE, KYOGIJO_JUDGING_STYLE } from "./judging.style.ts";
|
|
7
12
|
export { JUDGING_WORDS } from "./judging.words.ts";
|
|
8
13
|
export type { JudgingWords } from "./judging.words.ts";
|
|
9
14
|
export type { JudgingAssignment, JudgingMat, JudgingOfficial, JudgingOptions, JudgingResolved, JudgingSeat, JudgingStyle } from "./judging.types.ts";
|
package/dist/judging-entry.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
// A judging assignment: the officials of each mat area of a judo tournament, by seat, with their names and IDs, in the seat where they fit and in a chart where they do not; in 2D and in 3D.
|
|
2
|
+
export { judgingBoard, boardFoot, BOARD_BASE } from "./judging.board.js";
|
|
3
|
+
export { JUDGING_PAPER, judgingPrint, judgingPrintSheets, judgingPrintStyle } from "./judging.print.js";
|
|
4
|
+
export { KYOGIJO_JUDGING_BROADCAST_STYLE, mountJudgingBroadcast } from "./judging.mount.js";
|
|
5
|
+
export { BROADCAST_RATIO } from "./judging.broadcast.js";
|
|
2
6
|
export { drawJudging, judgingChart, judgingDrawing, judgingTable, judgingText } from "./judging.draw.js";
|
|
3
7
|
export { JUDGING_HEIGHTS, JUDGING_PRESETS, buildJudgingTurn, judgingTurnMarkup, mountJudgingTurn } from "./judging.turn.js";
|
|
4
8
|
export { JUDGING_LEAGUE, JUDGING_MATS_MAX, JUDGING_SEATS, JUDGING_SEAT_COUNT, JUDGING_SEAT_WORDS, JUDGING_STYLES } from "./judging.data.js";
|
|
5
9
|
export { JUDGING_LIMITS, benchOf, judgingPlan, judgingSetting, matLabel, seatIn, seatOf, seatsOf } from "./judging.js";
|
|
6
10
|
export { fitCard, fitChart, fitSeats, wrapText } from "./judging.fit.js";
|
|
7
|
-
export { KYOGIJO_JUDGING_STYLE } from "./judging.style.js";
|
|
11
|
+
export { KYOGIJO_JUDGING_BOARD_STYLE, KYOGIJO_JUDGING_STYLE } from "./judging.style.js";
|
|
8
12
|
export { JUDGING_WORDS } from "./judging.words.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type JudgingSetting } from "./judging.ts";
|
|
2
|
+
import type { JudgingOptions, JudgingResolved } from "./judging.types.ts";
|
|
3
|
+
/** The width a board is laid out in before it is scaled to the picture: every other figure here is a share of it. */
|
|
4
|
+
export declare const BOARD_BASE = 480;
|
|
5
|
+
/** One board as markup at (x, y), `width` wide, and how tall it came out. */
|
|
6
|
+
export interface BoardPlace {
|
|
7
|
+
markup: string;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}
|
|
11
|
+
/** The line at the board's foot: the mat's own line (`Round 2`) and the style (`Kata, 5 judges`). */
|
|
12
|
+
export declare function boardFoot(mat: JudgingResolved, setting: Pick<JudgingSetting, "language" | "style">): string;
|
|
13
|
+
/** The board of one mat at (x, y), `width` wide. */
|
|
14
|
+
export declare function boardMarkup(mat: JudgingResolved, setting: Pick<JudgingSetting, "language" | "style">, x: number, y: number, width: number): BoardPlace;
|
|
15
|
+
/**
|
|
16
|
+
* The board of an assignment on its own, as an SVG with nothing round it: the plate is the only thing that is drawn, semi-transparent, so that a page can lay it over a picture of the mat (the 3D view's). With several
|
|
17
|
+
* mats and no `mat`, their boards stand one under another.
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { judgingBoard } from "@johnmorrisdotca/kyogijo-stadiums/judging";
|
|
21
|
+
* const svg = judgingBoard({ style: "kata", mats: [{ label: "Mat 1", officials: [{ seat: 1, name: "Aiko Mori", id: "J-1042" }] }] });
|
|
22
|
+
* console.log(svg.includes("ky-ju-board"), svg.includes("Aiko Mori"));
|
|
23
|
+
* // true true
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function judgingBoard(options: JudgingOptions, resolved?: JudgingSetting): string;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// The board of a broadcast picture: the officials of one mat listed like a score panel on a television graphic. It is the package's own score panel drawn for officials (`budo.board.ts`): the same dark rounded plate, the
|
|
2
|
+
// mat's name where a score panel has the competition, the column heads, a row for each seat with its number on the round badge the seats on the mat wear and the name on a coloured chip as a team's is, the ID where a
|
|
3
|
+
// score would be, and the style under it where the foot is. Same classes, so the same colours, faces and light and dark; a seat with nobody in it is a hollow badge and a dashed chip. Every size is in the picture's own
|
|
4
|
+
// units and proportional to its width, and text is only ever set at a size: it is never stretched. Nothing here decides where the board goes.
|
|
5
|
+
import { el, esc, hash, num } from "./format.js";
|
|
6
|
+
import { PLAN_CARD, badge } from "./judging.card.js";
|
|
7
|
+
import { fitChart } from "./judging.fit.js";
|
|
8
|
+
import { JUDGING_LEAGUE } from "./judging.data.js";
|
|
9
|
+
import { judgingSetting } from "./judging.js";
|
|
10
|
+
import { KYOGIJO_JUDGING_BOARD_STYLE, KYOGIJO_JUDGING_STYLE } from "./judging.style.js";
|
|
11
|
+
import { judgingText } from "./judging.text.js";
|
|
12
|
+
import { JUDGING_WORDS } from "./judging.words.js";
|
|
13
|
+
import { fill } from "./strings.js";
|
|
14
|
+
import { metaMarkup, safeClass } from "./common.js";
|
|
15
|
+
import { LINE_HEIGHT, fitLines, textWidth } from "./text.js";
|
|
16
|
+
import { VERSION } from "./version.js";
|
|
17
|
+
/** The width a board is laid out in before it is scaled to the picture: every other figure here is a share of it. */
|
|
18
|
+
export const BOARD_BASE = 480;
|
|
19
|
+
/** The line at the board's foot: the mat's own line (`Round 2`) and the style (`Kata, 5 judges`). */
|
|
20
|
+
export function boardFoot(mat, setting) {
|
|
21
|
+
const style = fill(JUDGING_WORDS[setting.language].styleName[setting.style], { count: mat.seats.length });
|
|
22
|
+
return [mat.line, style].filter((part) => part !== "").join(" · ");
|
|
23
|
+
}
|
|
24
|
+
/** The text of a board's lines, centred on x: each line `size` tall, the first one's middle at `top`. */
|
|
25
|
+
function lines(rows, size, x, top, cls) {
|
|
26
|
+
return rows.map((row, i) => el("text", { class: cls, x, y: top + (i + 0.5) * size * LINE_HEIGHT + size * 0.3, "font-size": size, "text-anchor": "middle" }, esc(row))).join("");
|
|
27
|
+
}
|
|
28
|
+
/** A name on its chip: on one line where it stays at a size that reads (21 and up on a board 480 wide), else wrapped at its spaces, or broken inside a word, at a size no smaller than 17: the row grows to hold it. */
|
|
29
|
+
function nameFit(name, room, k) {
|
|
30
|
+
const size = Math.min(27 * k, room / Math.max(1, textWidth(name)));
|
|
31
|
+
if (size >= 21 * k)
|
|
32
|
+
return { name: [name], nameSize: size, id: [], idSize: 0, width: textWidth(name) * size, height: size * LINE_HEIGHT };
|
|
33
|
+
return fitChart({ name, id: "", idLabel: "", width: room, max: 27 * k, min: 17 * k });
|
|
34
|
+
}
|
|
35
|
+
/** The board of one mat at (x, y), `width` wide. */
|
|
36
|
+
export function boardMarkup(mat, setting, x, y, width) {
|
|
37
|
+
const words = JUDGING_WORDS[setting.language];
|
|
38
|
+
const k = width / BOARD_BASE;
|
|
39
|
+
const pad = 18 * k;
|
|
40
|
+
const badgeR = 21 * k;
|
|
41
|
+
const chipX = pad + 56 * k;
|
|
42
|
+
const chipW = 244 * k;
|
|
43
|
+
const idX = chipX + chipW + 12 * k;
|
|
44
|
+
const idW = width - pad - idX;
|
|
45
|
+
const rowMin = 60 * k;
|
|
46
|
+
const headH = 30 * k;
|
|
47
|
+
let out = "";
|
|
48
|
+
let cursor = 0;
|
|
49
|
+
// The title: the mat's name, where a score panel has the competition.
|
|
50
|
+
const title = fitLines(mat.label, width - 2 * pad, 52 * k, 42 * k);
|
|
51
|
+
const titleH = Math.max(64 * k, title.lines.length * title.size * LINE_HEIGHT + 26 * k);
|
|
52
|
+
out += lines(title.lines, title.size, width / 2, (titleH - title.lines.length * title.size * LINE_HEIGHT) / 2, "ky-text ky-comp ky-ju-board-title");
|
|
53
|
+
cursor += titleH;
|
|
54
|
+
// The column heads.
|
|
55
|
+
const head = (text, cx, room) => el("text", { class: "ky-text ky-foot", x: cx, y: cursor + headH / 2 + 5 * k, "font-size": Math.max(1, Math.min(15 * k, room / Math.max(1, textWidth(text)))), "text-anchor": "middle" }, esc(text));
|
|
56
|
+
out += head(words.chart.name, chipX + chipW / 2, chipW * 0.9) + head(words.chart.id, idX + idW / 2, idW * 0.9);
|
|
57
|
+
cursor += headH;
|
|
58
|
+
// A row for each seat, as tall as its name and its ID need.
|
|
59
|
+
for (const a of mat.seats) {
|
|
60
|
+
const name = a.assigned && a.name !== "" ? nameFit(a.name, chipW - 22 * k, k) : undefined;
|
|
61
|
+
const id = a.id === "" ? undefined : fitChart({ name: a.id, id: "", idLabel: "", width: idW - 8 * k, max: 25 * k, min: 15 * k });
|
|
62
|
+
const rowH = Math.max(rowMin, (name?.height ?? 0) + 22 * k, (id?.height ?? 0) + 22 * k);
|
|
63
|
+
const cy = cursor + rowH / 2;
|
|
64
|
+
let row = "";
|
|
65
|
+
row += badge(PLAN_CARD, pad + 26 * k, cy, badgeR, a.seat.n, a.assigned);
|
|
66
|
+
const chipH = rowH - 10 * k;
|
|
67
|
+
row += el("rect", { class: a.assigned ? "ky-panel-left ky-ju-chip" : "ky-ju-chip-empty", x: chipX, y: cursor + 5 * k, width: chipW, height: chipH, rx: Math.min(chipH * 0.22, 14 * k) });
|
|
68
|
+
if (name === undefined) {
|
|
69
|
+
row += el("text", { class: "ky-text ky-ju-board-vacant", x: chipX + chipW / 2, y: cy + 19 * k * 0.36, "font-size": 19 * k, "text-anchor": "middle" }, esc(words.chart.vacant));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
row += lines(name.name, name.nameSize, chipX + chipW / 2, cy - (name.name.length * name.nameSize * LINE_HEIGHT) / 2, "ky-text ky-ink-left");
|
|
73
|
+
}
|
|
74
|
+
if (id !== undefined)
|
|
75
|
+
row += lines(id.name, id.nameSize, idX + idW / 2, cy - (id.name.length * id.nameSize * LINE_HEIGHT) / 2, "ky-text ky-score ky-ju-board-id");
|
|
76
|
+
out += el("g", { class: "ky-ju-board-row", "data-mat": mat.n, "data-seat": a.seat.id }, row);
|
|
77
|
+
cursor += rowH;
|
|
78
|
+
}
|
|
79
|
+
// The foot: the line and the style.
|
|
80
|
+
const foot = boardFoot(mat, setting);
|
|
81
|
+
const footSize = Math.max(1, Math.min(21 * k, ((width - 2 * pad) * 0.98) / Math.max(1, textWidth(foot))));
|
|
82
|
+
const footH = 48 * k;
|
|
83
|
+
out += el("text", { class: "ky-text ky-foot", x: width / 2, y: cursor + footH / 2 + footSize * 0.34, "font-size": footSize, "text-anchor": "middle" }, esc(foot));
|
|
84
|
+
cursor += footH;
|
|
85
|
+
const plate = el("rect", { class: "ky-plate-bg", x: 0, y: 0, width, height: cursor, rx: Math.min(30 * k, width * 0.05) });
|
|
86
|
+
return { markup: el("g", { class: "ky-plate ky-ju-board", "data-mat": mat.n, transform: `translate(${num(x)} ${num(y)})` }, plate + out), width, height: cursor };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The board of an assignment on its own, as an SVG with nothing round it: the plate is the only thing that is drawn, semi-transparent, so that a page can lay it over a picture of the mat (the 3D view's). With several
|
|
90
|
+
* mats and no `mat`, their boards stand one under another.
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { judgingBoard } from "@johnmorrisdotca/kyogijo-stadiums/judging";
|
|
94
|
+
* const svg = judgingBoard({ style: "kata", mats: [{ label: "Mat 1", officials: [{ seat: 1, name: "Aiko Mori", id: "J-1042" }] }] });
|
|
95
|
+
* console.log(svg.includes("ky-ju-board"), svg.includes("Aiko Mori"));
|
|
96
|
+
* // true true
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function judgingBoard(options, resolved) {
|
|
100
|
+
const setting = resolved ?? judgingSetting(options);
|
|
101
|
+
const width = setting.width;
|
|
102
|
+
const gid = safeClass(options.id).replace(/ /g, "-") || `ky-jb-${hash(JSON.stringify([options, VERSION]))}`;
|
|
103
|
+
let y = 0;
|
|
104
|
+
let body = "";
|
|
105
|
+
for (const mat of setting.mats) {
|
|
106
|
+
const placed = boardMarkup(mat, setting, 0, y, width);
|
|
107
|
+
body += placed.markup;
|
|
108
|
+
y += placed.height + 24 * (width / BOARD_BASE);
|
|
109
|
+
}
|
|
110
|
+
const height = Math.ceil(y - 24 * (width / BOARD_BASE));
|
|
111
|
+
const { title, description } = judgingText(setting, options, false, "broadcast");
|
|
112
|
+
const css = options.css === "none" ? "" : `<style>${KYOGIJO_JUDGING_BOARD_STYLE}\n${KYOGIJO_JUDGING_STYLE}</style>`;
|
|
113
|
+
return el("svg", {
|
|
114
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
115
|
+
class: `kyogijo ky-judging ky-judging-board${safeClass(options.className) === "" ? "" : ` ${safeClass(options.className)}`}`,
|
|
116
|
+
viewBox: `0 0 ${num(width)} ${num(height)}`,
|
|
117
|
+
role: "img",
|
|
118
|
+
"aria-labelledby": `${gid}-t ${gid}-d`,
|
|
119
|
+
"data-judging": setting.style,
|
|
120
|
+
"data-league": JUDGING_LEAGUE[setting.style].league,
|
|
121
|
+
"data-view": "board",
|
|
122
|
+
"data-theme": options.theme === "light" || options.theme === "dark" ? options.theme : undefined,
|
|
123
|
+
"data-version": VERSION,
|
|
124
|
+
}, metaMarkup(`${gid}-t`, title, `${gid}-d`, description) + css + body);
|
|
125
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { JudgingDrawing } from "./judging.draw.ts";
|
|
2
|
+
import { type JudgingSetting } from "./judging.ts";
|
|
3
|
+
import type { JudgingOptions } from "./judging.types.ts";
|
|
4
|
+
/** The picture's shape: a television's. */
|
|
5
|
+
export declare const BROADCAST_RATIO: number;
|
|
6
|
+
export declare function broadcastDrawing(options: JudgingOptions, setting: JudgingSetting): JudgingDrawing;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// The broadcast picture of an assignment: the mat large, as a television would show it, 16:9, with the officials on a board at its side like a graphic and the seats' number badges where the officials sit. The board
|
|
2
|
+
// is the score panel's own look (`judging.board.ts`) and never lies over the contest area: the mat is fitted into the room the board leaves, so the middle of the contest area is clear whatever the names are. The whole
|
|
3
|
+
// picture scales evenly when it is shown, type and all; no text in it is stretched. The same options always give the same string.
|
|
4
|
+
import { metaMarkup, safeClass } from "./common.js";
|
|
5
|
+
import { el, hash, num } from "./format.js";
|
|
6
|
+
import { boardMarkup } from "./judging.board.js";
|
|
7
|
+
import { metricsOf, planMarkup, surfacesOf } from "./judging.plan.js";
|
|
8
|
+
import { judgingPlan } from "./judging.js";
|
|
9
|
+
import { KYOGIJO_JUDGING_STYLE } from "./judging.style.js";
|
|
10
|
+
import { judgingText } from "./judging.text.js";
|
|
11
|
+
import { VERSION } from "./version.js";
|
|
12
|
+
/** The picture's shape: a television's. */
|
|
13
|
+
export const BROADCAST_RATIO = 16 / 9;
|
|
14
|
+
/** The board's share of the picture's width, where it stands (from the right edge) and how far down. */
|
|
15
|
+
const BOARD = { width: 0.32, margin: 0.025, top: 0.03 };
|
|
16
|
+
export function broadcastDrawing(options, setting) {
|
|
17
|
+
const width = setting.width;
|
|
18
|
+
const frameH = Math.round(width / BROADCAST_RATIO);
|
|
19
|
+
const gap = 0.02 * width;
|
|
20
|
+
const m = metricsOf(width);
|
|
21
|
+
const geom = judgingPlan(setting.style);
|
|
22
|
+
// The camera is close: the tatami and the seats with a little round them, not the whole free zone of the plan, so that the mat fills the picture's height.
|
|
23
|
+
const near = [geom.plan.judo.tatami, geom.table, ...geom.places.flatMap((p) => [p.card, p.chair])];
|
|
24
|
+
const away = 0.6;
|
|
25
|
+
const region = setting.focus === "bench" ? geom.bench : { x0: Math.min(...near.map((b) => b.x0)) - away, y0: Math.min(...near.map((b) => b.y0)) - away, x1: Math.max(...near.map((b) => b.x1)) + away, y1: Math.max(...near.map((b) => b.y1)) + away };
|
|
26
|
+
const gid = safeClass(options.id).replace(/ /g, "-") || `ky-ju-${hash(JSON.stringify([options, "broadcast", VERSION]))}`;
|
|
27
|
+
const { surfaces, style, look } = surfacesOf(setting, options, gid);
|
|
28
|
+
const cards = [];
|
|
29
|
+
const boards = [];
|
|
30
|
+
let body = "";
|
|
31
|
+
let y = 0;
|
|
32
|
+
setting.mats.forEach((mat, i) => {
|
|
33
|
+
// The board first: as wide as its share, narrowed when a tall list would not fit the picture's height.
|
|
34
|
+
let bw = BOARD.width * width;
|
|
35
|
+
let placed = boardMarkup(mat, setting, 0, 0, bw);
|
|
36
|
+
for (let tries = 0; tries < 4 && placed.height > 0.94 * frameH; tries += 1) {
|
|
37
|
+
bw *= (0.94 * frameH) / placed.height * 0.99;
|
|
38
|
+
placed = boardMarkup(mat, setting, 0, 0, bw);
|
|
39
|
+
}
|
|
40
|
+
const bx = width - bw - BOARD.margin * width;
|
|
41
|
+
const by = y + Math.min(BOARD.top * width, (frameH - placed.height) / 2);
|
|
42
|
+
const board = boardMarkup(mat, setting, bx, by, bw);
|
|
43
|
+
// The mat in the room to the left of the board, as large as it will go.
|
|
44
|
+
const room = { x: 0, y, w: bx - 0.02 * width, h: frameH };
|
|
45
|
+
const plan = planMarkup(mat, surfaces[i], geom, region, room, m, setting, `${gid}-c${mat.n}`, false);
|
|
46
|
+
const contest = geom.plan.judo.contests[Math.min(i, geom.plan.judo.contests.length - 1)];
|
|
47
|
+
const centre = { x: plan.x + (((contest.x0 + contest.x1) / 2) - region.x0) * plan.scale, y: plan.y + (((contest.y0 + contest.y1) / 2) - region.y0) * plan.scale };
|
|
48
|
+
mat.seats.forEach((a, k) => cards.push({ mat: mat.n, seat: a.seat.id, fits: plan.fits[k] }));
|
|
49
|
+
boards.push({ mat: mat.n, x: bx, y: by, width: board.width, height: board.height, plan: { x: plan.x, y: plan.y, width: plan.width, height: plan.height }, centre });
|
|
50
|
+
body += el("g", { class: "ky-ju-panel ky-ju-frame", "data-mat": mat.n }, el("rect", { class: "ky-apron", x: 0, y, width, height: frameH }) + plan.markup + board.markup);
|
|
51
|
+
y += frameH + gap;
|
|
52
|
+
});
|
|
53
|
+
const height = Math.round(y - gap);
|
|
54
|
+
const { title, description } = judgingText(setting, options, false, "broadcast");
|
|
55
|
+
const css = options.css === "none" ? "" : `<style>${style}\n${KYOGIJO_JUDGING_STYLE}</style>`;
|
|
56
|
+
const root = el("svg", {
|
|
57
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
58
|
+
class: `kyogijo ky-judging ky-judo${safeClass(options.className) === "" ? "" : ` ${safeClass(options.className)}`}`,
|
|
59
|
+
viewBox: `0 0 ${num(width)} ${num(height)}`,
|
|
60
|
+
role: "img",
|
|
61
|
+
"aria-labelledby": `${gid}-t ${gid}-d`,
|
|
62
|
+
"data-sport": "judo",
|
|
63
|
+
"data-judging": setting.style,
|
|
64
|
+
"data-view": "broadcast",
|
|
65
|
+
"data-look": look ?? "yellow-red",
|
|
66
|
+
"data-mats": setting.total,
|
|
67
|
+
"data-chart": "no",
|
|
68
|
+
"data-theme": options.theme === "light" || options.theme === "dark" ? options.theme : undefined,
|
|
69
|
+
"data-version": VERSION,
|
|
70
|
+
}, metaMarkup(`${gid}-t`, title, `${gid}-d`, description) + css + body);
|
|
71
|
+
return { svg: root, width, height, chart: false, cards, title, description, boards };
|
|
72
|
+
}
|
package/dist/judging.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare const JUDGING_LIMITS: Readonly<{
|
|
|
6
6
|
name: 120;
|
|
7
7
|
id: 64;
|
|
8
8
|
label: 40;
|
|
9
|
+
line: 60;
|
|
9
10
|
}>;
|
|
10
11
|
/** The seats of a style: every one, or without the optional ones (the side judges of a contest). @throws TypeError for a style that is not one. */
|
|
11
12
|
export declare function seatsOf(style: unknown, only?: "all" | "listed"): readonly JudgingSeat[];
|
|
@@ -16,6 +17,8 @@ export declare function seatsOf(style: unknown, only?: "all" | "listed"): readon
|
|
|
16
17
|
export declare function seatOf(style: JudgingStyle, seat: unknown): JudgingSeat;
|
|
17
18
|
/** The label of a mat: the caller's, held to its length, else the language's `Mat {n}`. */
|
|
18
19
|
export declare function matLabel(mat: JudgingMat, n: number, language: Language): string;
|
|
20
|
+
/** The line of a mat's broadcast board: the caller's, held to its length, or nothing. */
|
|
21
|
+
export declare function matLine(mat: JudgingMat): string;
|
|
19
22
|
/** What `drawJudging` and the 3D view work from: the options held to what they may be, and every mat with all of its seats. */
|
|
20
23
|
export interface JudgingSetting {
|
|
21
24
|
style: JudgingStyle;
|
|
@@ -25,9 +28,13 @@ export interface JudgingSetting {
|
|
|
25
28
|
/** How many mats the assignment has altogether. */
|
|
26
29
|
total: number;
|
|
27
30
|
chart: "auto" | "always" | "never";
|
|
31
|
+
/** `plan`: the plan with its chart; `broadcast`: the mat large with the board at its side. */
|
|
32
|
+
view: "plan" | "broadcast";
|
|
28
33
|
orientation: "landscape" | "portrait";
|
|
29
34
|
focus: "mat" | "bench";
|
|
30
35
|
width: number;
|
|
36
|
+
/** Whether the names are on the seats (`seatNames`). */
|
|
37
|
+
seatNames: boolean;
|
|
31
38
|
}
|
|
32
39
|
/**
|
|
33
40
|
* Hold the options to what they may be and put each official in a seat.
|
package/dist/judging.draw.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export { judgingText } from "./judging.text.ts";
|
|
2
2
|
import type { JudgingOptions } from "./judging.types.ts";
|
|
3
3
|
/** What a drawing of an assignment is, and what was worked out to make it. */
|
|
4
4
|
export interface JudgingDrawing {
|
|
@@ -16,12 +16,25 @@ export interface JudgingDrawing {
|
|
|
16
16
|
}[];
|
|
17
17
|
title: string;
|
|
18
18
|
description: string;
|
|
19
|
+
/** The broadcast view: where each mat's board is and where the part of the mat that is shown is and where the middle of its contest area is, in the picture's units (the board lies over neither). Empty for the plan view. */
|
|
20
|
+
boards: {
|
|
21
|
+
mat: number;
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
plan: {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
};
|
|
32
|
+
centre: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
};
|
|
36
|
+
}[];
|
|
19
37
|
}
|
|
20
|
-
/** The title and the description of an assignment: each mat with each seat and who is in it. */
|
|
21
|
-
export declare function judgingText(setting: JudgingSetting, options: Pick<JudgingOptions, "title" | "description">, chart: boolean): {
|
|
22
|
-
title: string;
|
|
23
|
-
description: string;
|
|
24
|
-
};
|
|
25
38
|
/** The picture of an assignment and what was worked out to make it. `mode` `chart` is the chart alone (for beside a 3D view). */
|
|
26
39
|
export declare function judgingDrawing(options: JudgingOptions, mode?: "full" | "chart"): JudgingDrawing;
|
|
27
40
|
/**
|