@johnmorrisdotca/kyogijo-stadiums 0.16.1 → 0.18.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 +21 -0
- package/README.md +22 -7
- package/dist/budo/judo.d.ts +4 -0
- package/dist/budo/judo.js +1 -1
- package/dist/judging-entry.d.ts +12 -0
- package/dist/judging-entry.js +8 -0
- package/dist/judging.card.d.ts +21 -0
- package/dist/judging.card.js +34 -0
- package/dist/judging.d.ts +74 -0
- package/dist/judging.data.d.ts +16 -0
- package/dist/judging.data.js +53 -0
- package/dist/judging.draw.d.ts +66 -0
- package/dist/judging.draw.js +293 -0
- package/dist/judging.fit.d.ts +54 -0
- package/dist/judging.fit.js +95 -0
- package/dist/judging.js +197 -0
- package/dist/judging.style.d.ts +8 -0
- package/dist/judging.style.js +30 -0
- package/dist/judging.turn.d.ts +36 -0
- package/dist/judging.turn.js +169 -0
- package/dist/judging.types.d.ts +78 -0
- package/dist/judging.types.js +1 -0
- package/dist/judging.words.d.ts +46 -0
- package/dist/judging.words.js +40 -0
- package/dist/multi.turn.js +1 -9
- package/dist/strings.d.ts +1 -1
- package/dist/strings.js +2 -2
- package/dist/turn.kit.d.ts +13 -2
- package/dist/turn.kit.js +9 -0
- package/dist/turn.markup.js +1 -1
- package/dist/turn.model.d.ts +2 -0
- package/dist/turn.style.js +15 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -1
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.18.0] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Shiai judging assignments** (`style: "shiai"` of `@johnmorrisdotca/kyogijo-stadiums/judging`). A contest area's officials by seat, with a name and an ID, drawn as the kata area's are (a card in the seat where the name fits, the chart of seat, role, name and ID that never cuts a name, 2D and 3D, light and dark, English and Japanese, `mat`, `focus`, `chart`, `orientation`, `judgingTable`). From the IJF Sport and Organisation Rules of 21 January 2026: **the referee**, on the tatami at its centre 2 m back from the line the athletes start on, facing the technical table (Article 9; the Refereeing Rules' Article 2); **the timekeeper and the scorekeeper**, the two technical officials a tatami should have for timing and scoring (the Refereeing Rules' opening article); **the referee supervisor**, on the technical table with the CARE replay system (the same article); and **two side judges**, for an event with no CARE system (Article 13, 5), drawn only with the new `sideJudges: true` or when a mat names them. Which chair at the table is whose, the side judges' places (two opposite corners of the contest area, 2 m out: the Rules give none), the chairs, the table and the cards are ours. In the close-up of the bench (`focus: "bench"`) only the table's seats are drawn and the referee's and side judges' names are in the chart; in 3D the referee's and a side judge's cards stand on posts. Seat words: `referee`, `timekeeper`, `scorekeeper`, `supervisor`, `side-judge-1`, `side-judge-2` (or their numbers 1 to 6, or `judge-1`, `scorer`, `jury`...). The demo, [judging assignments](https://johnmorrisdotca.github.io/kyogijo-stadiums/judging.html), has a Style choice (`style=shiai`), the side judges' checkbox and a row in its editor for each seat; the docs have [a section](./docs/judging.md#the-seats-of-a-contest) and the gallery [a contest](https://johnmorrisdotca.github.io/kyogijo-stadiums/docs/gallery-judging.html#shiai).
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- `JudgingStyle` is `"kata" | "shiai"`; `JudgingSeat` has `where` (`table`, `mat` or `corner`) and `optional`, and its `role` the contest's roles; `seatsOf(style, "listed")` leaves out the optional seats; `judgingPlan(style, count)` gives each mat's `places` (a chair and a card for each seat, in metres) and its bench; `fitSeats` takes a box for each seat. A kata assignment draws byte for byte what it did.
|
|
19
|
+
- `JudoLayout` (the judo plan) also gives `desks` (the technical tables) and `free` (the free zone), as data only: no drawing changes.
|
|
20
|
+
|
|
21
|
+
## [0.17.0] - 2026-10-20
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Judging assignments** (`@johnmorrisdotca/kyogijo-stadiums/judging`: `drawJudging`, `judgingChart`, `judgingTable`, `judgingDrawing`, `mountJudgingTurn`, `judgingTurnMarkup`, `buildJudgingTurn`). Who judges where at a judo tournament: `{ style: "kata", mats: [{ label, officials: [{ seat, name, id }] }] }` gives one SVG for a tablet read live: for each of 1 to 6 mats the judo kata area with a badge at each of the five judges' seats (the seats are the plan's own, 1.25 m apart, the central judge at the centre), the name and the ID in a card in the seat where they fit, and beside the plan (landscape) or under it (portrait) a chart of seat, role, name and ID whose rows grow until every name (up to 120 characters) and ID (up to 64) is whole; a seat with nobody in it says so. A name fits a seat only at a type no smaller than 1.2 % of the picture's width; the cards of a mat share one size; `chart` is `auto` (drawn when a name does not fit, the plan first being given the room the chart would take), `always` or `never`; `mat` draws one mat alone (a tab); `focus: "bench"` shows the judges' bench close up so that the names are as large as they can be. In 3D the judges' table and chairs stand on the judo floor, a name card stands on the table in front of each judge and turns to face the eye, and the mat's name is on a sign over it (`focus: "bench"` fits and turns the view about the bench; the chart goes beside it). Light and dark, English and Japanese, a title and a description that name every seat, and `judgingTable` as a table. The numbering of the seats (1 to 5 from the left of the plan, the central judge 3), the cards, the chart and the heights in 3D are ours: no rule gives them. Data stays with the caller: nothing is fetched, stored or sent; every text is made safe and held to its length. Docs: [judging assignments](./docs/judging.md) and [a gallery](https://johnmorrisdotca.github.io/kyogijo-stadiums/docs/gallery-judging.html). Demo: <https://johnmorrisdotca.github.io/kyogijo-stadiums/judging.html> (a tab for each mat, editable names and IDs kept in its address). Shiai (a referee and judges by the IJF's refereeing positions) is the next release.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `TurnModel` has an optional `lens`, a lens of the model's own used when the settings give none (a view of several benches at once has a longer one); the helpers `box` and `rect` moved from `multi.turn.ts` to `turn.kit.ts`; the 3D view's stylesheet carries the colours and rules of a judging assignment's cards (`--ky-ju-*`, `u-card*`, `u-sign*`, `u-bench*`); `UprightKind` has `judges` and `PartKind` has `card` and `sign`.
|
|
30
|
+
|
|
10
31
|
## [0.16.1] - 2026-10-20
|
|
11
32
|
|
|
12
33
|
### Added
|
package/README.md
CHANGED
|
@@ -102,6 +102,7 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
102
102
|
- **Data on the surface.** Points, lines, arrows, text, heat maps, hexagons, zone charts and density contours over any surface, in its feet or a data provider's frame, cut to its outline, with a table for each layer; ready-made shot and pass charts. [Data layers](./docs/layers.md), [charts](./docs/charts.md).
|
|
103
103
|
- **Small multiples and backgrounds.** `drawGrid` puts many drawings in one SVG, under a title and a subtitle, over a credit line, with a key they share, in a size for a social card, a square post or a phone; `background` lays a quiet pattern (felt, grass, wood, ice, paper, a grid, dots) or a photograph behind a drawing or a grid. [Layouts and backgrounds](./docs/layouts.md).
|
|
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
|
+
- **Judging assignments.** Who judges where. [Judging](./docs/judging.md).
|
|
105
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).
|
|
106
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, the walls of padel and squash, a pool's blocks, a table tennis area's surrounds); and the venue round it (raked stands, roofs on request, a dojo's walls and gallery). Plain DOM and CSS. [The 3D view](./docs/turn.md).
|
|
107
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).
|
|
@@ -131,6 +132,7 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
131
132
|
| `./turn` | A surface as a 3D view that turns, with the net, basket, goal or posts standing on it. |
|
|
132
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`). |
|
|
133
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)). |
|
|
134
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. |
|
|
135
137
|
| `./mount`, `./react`, `./element`, `./element/define` | Draw into a container; React props; the `<kyogijo-field>` element and its registration. |
|
|
136
138
|
|
|
@@ -366,12 +368,12 @@ console.log(items.map((item) => item.kind).join(), html.includes("preserve-3d"))
|
|
|
366
368
|
// net,netposts,antennae false
|
|
367
369
|
```
|
|
368
370
|
|
|
369
|
-
The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewpoints
|
|
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 a flat rectangle placed by one `matrix3d`, so there is no 3D context for a phone to lose. In the element it is `<kyogijo-field sport="nhl" turn turn-view="broadcast">`. [The 3D view](./docs/turn.md).
|
|
370
372
|
|
|
371
373
|
<p align="center">
|
|
372
374
|
<picture>
|
|
373
375
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-volleyball-desk-dark.webp">
|
|
374
|
-
<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
|
|
376
|
+
<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 antennae, and the viewpoint buttons under it." width="640">
|
|
375
377
|
</picture>
|
|
376
378
|
<br><em>A volleyball net at its rulebook height, with its posts and antennae.</em>
|
|
377
379
|
</p>
|
|
@@ -379,7 +381,7 @@ The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewp
|
|
|
379
381
|
<p align="center">
|
|
380
382
|
<picture>
|
|
381
383
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-rink-desk-dark.webp">
|
|
382
|
-
<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
|
|
384
|
+
<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: the boards and glass round the ice, a goal at each end, and the score on the ice." width="640">
|
|
383
385
|
</picture>
|
|
384
386
|
<br><em>A rink with its boards, glass and goals.</em>
|
|
385
387
|
</p>
|
|
@@ -387,7 +389,7 @@ The flat drawing is the floor, turned by a drag, a swipe, the keys or four viewp
|
|
|
387
389
|
<p align="center">
|
|
388
390
|
<picture>
|
|
389
391
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/turn-court-desk-dark.webp">
|
|
390
|
-
<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
|
|
392
|
+
<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: a basket on its backboard and padded stanchion at each end." width="640">
|
|
391
393
|
</picture>
|
|
392
394
|
<br><em>A court with a basket at each end, the rim at 10 feet.</em>
|
|
393
395
|
</p>
|
|
@@ -465,7 +467,7 @@ console.log(svg.includes("3 shots"), svg.includes("By outcome: goal 1, shot 1, b
|
|
|
465
467
|
// true true
|
|
466
468
|
```
|
|
467
469
|
|
|
468
|
-
Zoom to a part
|
|
470
|
+
Zoom to a part with `range`: the data follows the crop ([display ranges](./docs/ranges.md)).
|
|
469
471
|
|
|
470
472
|
```ts
|
|
471
473
|
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";
|
|
@@ -475,7 +477,7 @@ console.log(zone.includes('data-range="offensive-zone"'), zone.includes("Shows o
|
|
|
475
477
|
// true true
|
|
476
478
|
```
|
|
477
479
|
|
|
478
|
-
Lines, arrows, text, heat maps, hexagons, zones and contours are in [data layers](./docs/layers.md);
|
|
480
|
+
Lines, arrows, text, heat maps, hexagons, zones and contours are in [data layers](./docs/layers.md); shot, spray and pass charts are one call each in [charts](./docs/charts.md); pass networks, formations, lineups, Voronoi cells and flow fields are layers too ([team shape](./docs/team-shape.md)).
|
|
479
481
|
|
|
480
482
|
### Small multiples on a card
|
|
481
483
|
|
|
@@ -539,7 +541,20 @@ console.log(layout.needs.length, layout.needs.width);
|
|
|
539
541
|
<br><em>Without `sample`: the empty places an organiser fills.</em>
|
|
540
542
|
</p>
|
|
541
543
|
|
|
542
|
-
The [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html)
|
|
544
|
+
The [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html) turns it in 3D.
|
|
545
|
+
|
|
546
|
+
### Who judges where
|
|
547
|
+
|
|
548
|
+
`drawJudging` puts each judo mat's officials by seat in the picture and in a chart ([judging](./docs/judging.md)).
|
|
549
|
+
|
|
550
|
+
<p align="center">
|
|
551
|
+
<picture>
|
|
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, with a name card before each judge." width="640">
|
|
554
|
+
</picture>
|
|
555
|
+
<br><em>Judges in 3D.</em>
|
|
556
|
+
</p>
|
|
557
|
+
|
|
543
558
|
|
|
544
559
|
### A table tennis area
|
|
545
560
|
|
package/dist/budo/judo.d.ts
CHANGED
|
@@ -43,6 +43,10 @@ export interface JudoLayout {
|
|
|
43
43
|
seats: MBox[];
|
|
44
44
|
coaches: MBox[];
|
|
45
45
|
};
|
|
46
|
+
/** A contest area's technical tables (ours: 3 m by 0.8 m), one for each area of the top row; empty for a kata area. */
|
|
47
|
+
desks: MBox[];
|
|
48
|
+
/** The free zone round the whole competition area. */
|
|
49
|
+
free: MBox;
|
|
46
50
|
}
|
|
47
51
|
/** The mats of a `tatami` option, or the league's own when none. @throws Error for a name that is not a size of mat. */
|
|
48
52
|
export declare function matOf(asked: BudoStyle["tatami"], fig: JudoFigures): MatSize;
|
package/dist/budo/judo.js
CHANGED
|
@@ -139,7 +139,7 @@ export function judoParts(o) {
|
|
|
139
139
|
if (judges.coaches.length > 0)
|
|
140
140
|
marks.push({ id: "coach-chair", x: (judges.coaches[0].x0 + judges.coaches[0].x1) / 2, y: (judges.coaches[0].y0 + judges.coaches[0].y1) / 2, side: "bottom" });
|
|
141
141
|
const extent = union([free, ...desks.map((d) => grow(d, 0.3)), ...[...judges.tables, ...judges.seats, ...judges.coaches].map((d) => grow(d, 0.3))]);
|
|
142
|
-
return { parts, tatami, extent, contests, gap, pieces, mat, marks, danger: band, judges };
|
|
142
|
+
return { parts, tatami, extent, contests, gap, pieces, mat, marks, danger: band, judges, desks, free };
|
|
143
143
|
}
|
|
144
144
|
/** The number of mats of the competition area: a half mat counts a half. */
|
|
145
145
|
export const mats = (layout, mat) => Math.round(matCount(layout.pieces, mat) * 100) / 100;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { drawJudging, judgingChart, judgingDrawing, judgingTable, judgingText } from "./judging.draw.ts";
|
|
2
|
+
export { JUDGING_HEIGHTS, JUDGING_PRESETS, buildJudgingTurn, judgingTurnMarkup, mountJudgingTurn } from "./judging.turn.ts";
|
|
3
|
+
export { JUDGING_LEAGUE, JUDGING_MATS_MAX, JUDGING_SEATS, JUDGING_SEAT_COUNT, JUDGING_SEAT_WORDS, JUDGING_STYLES } from "./judging.data.ts";
|
|
4
|
+
export { JUDGING_LIMITS, benchOf, judgingPlan, judgingSetting, matLabel, seatIn, seatOf, seatsOf } from "./judging.ts";
|
|
5
|
+
export { fitCard, fitChart, fitSeats, wrapText } from "./judging.fit.ts";
|
|
6
|
+
export { KYOGIJO_JUDGING_STYLE } from "./judging.style.ts";
|
|
7
|
+
export { JUDGING_WORDS } from "./judging.words.ts";
|
|
8
|
+
export type { JudgingWords } from "./judging.words.ts";
|
|
9
|
+
export type { JudgingAssignment, JudgingMat, JudgingOfficial, JudgingOptions, JudgingResolved, JudgingSeat, JudgingStyle } from "./judging.types.ts";
|
|
10
|
+
export type { JudgingDrawing } from "./judging.draw.ts";
|
|
11
|
+
export type { JudgingPlan, JudgingSetting, MatPlaces, SeatPlace } from "./judging.ts";
|
|
12
|
+
export type { CardAsk, CardFit } from "./judging.fit.ts";
|
|
@@ -0,0 +1,8 @@
|
|
|
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 { drawJudging, judgingChart, judgingDrawing, judgingTable, judgingText } from "./judging.draw.js";
|
|
3
|
+
export { JUDGING_HEIGHTS, JUDGING_PRESETS, buildJudgingTurn, judgingTurnMarkup, mountJudgingTurn } from "./judging.turn.js";
|
|
4
|
+
export { JUDGING_LEAGUE, JUDGING_MATS_MAX, JUDGING_SEATS, JUDGING_SEAT_COUNT, JUDGING_SEAT_WORDS, JUDGING_STYLES } from "./judging.data.js";
|
|
5
|
+
export { JUDGING_LIMITS, benchOf, judgingPlan, judgingSetting, matLabel, seatIn, seatOf, seatsOf } from "./judging.js";
|
|
6
|
+
export { fitCard, fitChart, fitSeats, wrapText } from "./judging.fit.js";
|
|
7
|
+
export { KYOGIJO_JUDGING_STYLE } from "./judging.style.js";
|
|
8
|
+
export { JUDGING_WORDS } from "./judging.words.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CardFit } from "./judging.fit.ts";
|
|
2
|
+
/** The class names a card is drawn with. */
|
|
3
|
+
export interface CardClasses {
|
|
4
|
+
card: string;
|
|
5
|
+
name: string;
|
|
6
|
+
id: string;
|
|
7
|
+
badge: string;
|
|
8
|
+
badgeEmpty: string;
|
|
9
|
+
n: string;
|
|
10
|
+
}
|
|
11
|
+
/** The classes of the plan. */
|
|
12
|
+
export declare const PLAN_CARD: CardClasses;
|
|
13
|
+
/** The classes of the 3D view's planes. */
|
|
14
|
+
export declare const TURN_CARD: CardClasses;
|
|
15
|
+
/** The round badge of a seat's number, centred at (cx, cy); hollow when nobody is in the seat. */
|
|
16
|
+
export declare function badge(cls: CardClasses, cx: number, cy: number, r: number, n: number, assigned: boolean): string;
|
|
17
|
+
/**
|
|
18
|
+
* A card with a name and an ID, `w` by `h` with its top left at (x, y): the text centred in the space under the badge, which straddles the card's top edge, and the badge itself. `fit` is what `fitCard` made of the
|
|
19
|
+
* name and the ID for the space inside `pad` and under `r`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function card(cls: CardClasses, fit: CardFit, n: number, x: number, y: number, w: number, h: number, pad: number, r: number, round: number): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// The name card of a seat and the badge of its number, as markup: the same drawing in the plan (in the picture's units, `ky-ju-*` classes) and in the 3D view (in feet, `u-card*` classes), so that a seat reads the same
|
|
2
|
+
// in both. Nothing here decides whether a name fits: `judging.fit.ts` does, and a card is drawn only for a name that does.
|
|
3
|
+
import { el, esc } from "./format.js";
|
|
4
|
+
import { LINE_HEIGHT } from "./text.js";
|
|
5
|
+
/** The classes of the plan. */
|
|
6
|
+
export const PLAN_CARD = { card: "ky-ju-card", name: "ky-ju-card-name", id: "ky-ju-card-id", badge: "ky-ju-badge", badgeEmpty: "ky-ju-badge ky-ju-badge-empty", n: "ky-ju-badge-n" };
|
|
7
|
+
/** The classes of the 3D view's planes. */
|
|
8
|
+
export const TURN_CARD = { card: "u-card", name: "u-card-name", id: "u-card-id", badge: "u-card-badge", badgeEmpty: "u-card-badge u-card-badge-empty", n: "u-card-n" };
|
|
9
|
+
/** The round badge of a seat's number, centred at (cx, cy); hollow when nobody is in the seat. */
|
|
10
|
+
export function badge(cls, cx, cy, r, n, assigned) {
|
|
11
|
+
return el("circle", { class: assigned ? cls.badge : cls.badgeEmpty, cx, cy, r }) + el("text", { class: cls.n, x: cx, y: cy + r * 0.36, "font-size": r * 1.05 }, String(n));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A card with a name and an ID, `w` by `h` with its top left at (x, y): the text centred in the space under the badge, which straddles the card's top edge, and the badge itself. `fit` is what `fitCard` made of the
|
|
15
|
+
* name and the ID for the space inside `pad` and under `r`.
|
|
16
|
+
*/
|
|
17
|
+
export function card(cls, fit, n, x, y, w, h, pad, r, round) {
|
|
18
|
+
const cx = x + w / 2;
|
|
19
|
+
const room = h - 2 * pad - r;
|
|
20
|
+
let out = el("rect", { class: cls.card, x, y, width: w, height: h, rx: round });
|
|
21
|
+
let cy = y + pad + r + Math.max(0, (room - fit.height) / 2);
|
|
22
|
+
for (const line of fit.name) {
|
|
23
|
+
out += el("text", { class: cls.name, x: cx, y: cy + fit.nameSize * 0.88, "font-size": fit.nameSize }, esc(line));
|
|
24
|
+
cy += fit.nameSize * LINE_HEIGHT;
|
|
25
|
+
}
|
|
26
|
+
if (fit.id.length > 0) {
|
|
27
|
+
cy += fit.name.length > 0 ? fit.nameSize * 0.28 : 0;
|
|
28
|
+
for (const line of fit.id) {
|
|
29
|
+
out += el("text", { class: cls.id, x: cx, y: cy + fit.idSize * 0.88, "font-size": fit.idSize }, esc(line));
|
|
30
|
+
cy += fit.idSize * LINE_HEIGHT;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out + badge(cls, cx, y, r, n, true);
|
|
34
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type BudoPlan, type MBox } from "./budo/plan.ts";
|
|
2
|
+
import type { JudgingMat, JudgingOptions, JudgingResolved, JudgingSeat, JudgingStyle } from "./judging.types.ts";
|
|
3
|
+
import type { Language } from "./types.ts";
|
|
4
|
+
/** The longest name, ID and mat label that are taken, in characters. */
|
|
5
|
+
export declare const JUDGING_LIMITS: Readonly<{
|
|
6
|
+
name: 120;
|
|
7
|
+
id: 64;
|
|
8
|
+
label: 40;
|
|
9
|
+
}>;
|
|
10
|
+
/** 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
|
+
export declare function seatsOf(style: unknown, only?: "all" | "listed"): readonly JudgingSeat[];
|
|
12
|
+
/**
|
|
13
|
+
* The seat a name stands for: its number (`3`, `"3"`), its key (`"judge-3"`, `"Judge 3"`, `"referee"`, `"timekeeper"`) or a word (`"central"`, `"scorer"`, `"jury"`).
|
|
14
|
+
* @throws RangeError for a seat the style does not have, naming the seats it has.
|
|
15
|
+
*/
|
|
16
|
+
export declare function seatOf(style: JudgingStyle, seat: unknown): JudgingSeat;
|
|
17
|
+
/** The label of a mat: the caller's, held to its length, else the language's `Mat {n}`. */
|
|
18
|
+
export declare function matLabel(mat: JudgingMat, n: number, language: Language): string;
|
|
19
|
+
/** 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
|
+
export interface JudgingSetting {
|
|
21
|
+
style: JudgingStyle;
|
|
22
|
+
language: Language;
|
|
23
|
+
/** The mats to draw (all of them, or the one `mat` names), each with every seat of the style. */
|
|
24
|
+
mats: JudgingResolved[];
|
|
25
|
+
/** How many mats the assignment has altogether. */
|
|
26
|
+
total: number;
|
|
27
|
+
chart: "auto" | "always" | "never";
|
|
28
|
+
orientation: "landscape" | "portrait";
|
|
29
|
+
focus: "mat" | "bench";
|
|
30
|
+
width: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Hold the options to what they may be and put each official in a seat.
|
|
34
|
+
* @throws TypeError for an option of the wrong kind, RangeError for a number of mats outside 1 to 6, a mat that does not exist, a seat the style does not have, a seat named twice on one mat or a text that is too long.
|
|
35
|
+
*/
|
|
36
|
+
export declare function judgingSetting(options: JudgingOptions): JudgingSetting;
|
|
37
|
+
/** Where one seat is on a mat's plan, in metres from the top left of the tatami: its chair (or the place where the official stands) and the card that carries the name, which may lie over the table in front of it. */
|
|
38
|
+
export interface SeatPlace {
|
|
39
|
+
chair: MBox;
|
|
40
|
+
card: MBox;
|
|
41
|
+
}
|
|
42
|
+
/** One mat's seats, in the order the style lists them (`JUDGING_SEATS`, optional seats included), its table and its bench. */
|
|
43
|
+
export interface MatPlaces {
|
|
44
|
+
places: SeatPlace[];
|
|
45
|
+
/** The judges' table or the technical table behind the seats at it. */
|
|
46
|
+
table: MBox;
|
|
47
|
+
/** The seats at the table close up: the picture of `focus: "bench"`. */
|
|
48
|
+
bench: MBox;
|
|
49
|
+
}
|
|
50
|
+
/** Where the seats are on the plan of a style, and the plan they are on. */
|
|
51
|
+
export interface JudgingPlan {
|
|
52
|
+
plan: BudoPlan;
|
|
53
|
+
/** Each mat's seats, for the mats side by side the plan has (`count`). */
|
|
54
|
+
mats: MatPlaces[];
|
|
55
|
+
/** The first mat's seats, its table and its bench, as `mats[0]` has them (the chairs of the seats, in order). */
|
|
56
|
+
places: SeatPlace[];
|
|
57
|
+
chairs: MBox[];
|
|
58
|
+
table: MBox;
|
|
59
|
+
bench: MBox;
|
|
60
|
+
/** The distance between two seats at the table. */
|
|
61
|
+
pitch: number;
|
|
62
|
+
/** The whole picture of a mat (the free zone, the table, the seats, their cards): what `focus: "mat"` shows, for the first mat. */
|
|
63
|
+
extent: MBox;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The judges' bench close up: the seats and their table with a little round them and a few rows of mats in front, from the seats of one mat or of several side by side. `matTop` is where the mats start (the top of the first
|
|
67
|
+
* contest area), so that the picture shows how the bench sits at the mat's edge; `front` instead says how far in front of the table the picture reaches, in metres (the 3D view, which turns, wants as little of the floor as
|
|
68
|
+
* will do).
|
|
69
|
+
*/
|
|
70
|
+
export declare function benchOf(chairs: readonly MBox[], table: MBox, pitch: number, matTop: number, front?: number): MBox;
|
|
71
|
+
/** The plan of `count` mats side by side of a style, with its seats: the package's own judo area, so that the seats named are the seats drawn. */
|
|
72
|
+
export declare function judgingPlan(style: JudgingStyle, count?: number): JudgingPlan;
|
|
73
|
+
/** Whether a seat is in a box: its card's middle is inside it. A seat that is not is not drawn in a close-up of the bench, and its name is in the chart only. */
|
|
74
|
+
export declare function seatIn(place: SeatPlace, box: MBox): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { JudgingSeat, JudgingStyle } from "./judging.types.ts";
|
|
2
|
+
/** How many officials a style seats at the most (a contest's two side judges included). */
|
|
3
|
+
export declare const JUDGING_SEAT_COUNT: Readonly<Record<JudgingStyle, number>>;
|
|
4
|
+
/** The seats of every style, in the order they are listed. */
|
|
5
|
+
export declare const JUDGING_SEATS: Readonly<Record<JudgingStyle, readonly JudgingSeat[]>>;
|
|
6
|
+
/** The other words a seat is asked for by, besides its key and its number. */
|
|
7
|
+
export declare const JUDGING_SEAT_WORDS: Readonly<Record<string, readonly string[]>>;
|
|
8
|
+
/** The styles that can be asked for. */
|
|
9
|
+
export declare const JUDGING_STYLES: readonly JudgingStyle[];
|
|
10
|
+
/** The league each style is drawn in (`drawKyogijo`'s `league`), and the sources its seats are read from (keys of `LEAGUE_SOURCES`). */
|
|
11
|
+
export declare const JUDGING_LEAGUE: Readonly<Record<JudgingStyle, {
|
|
12
|
+
league: string;
|
|
13
|
+
sources: readonly string[];
|
|
14
|
+
}>>;
|
|
15
|
+
/** The most mat areas an assignment names: the plan's own limit for areas side by side. */
|
|
16
|
+
export declare const JUDGING_MATS_MAX = 6;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// The seats of each judging style, as the rulebook has them.
|
|
2
|
+
// A kata area is judged by five judges on the shomen side, 1.25 m apart, the central judge at the centre of the area, and no referee (IJF Sport and Organisation Rules of 21 January 2026, B1.8 and the judges' article; the
|
|
3
|
+
// Kata Commission's Tournament Handbook 2024). The rules do not number the judges: the numbers here are ours, from the left as the plan lies with the shomen at the top (so the central judge is 3).
|
|
4
|
+
// A contest (shiai) has one referee, on the tatami at its centre 2 m back from the line the athletes start on, facing the technical table (SOR, Refereeing Rules, Article 9 and Article 2); two technical officials a
|
|
5
|
+
// tatami for timing and scoring (the Refereeing Rules' opening article); the IJF Referee Supervisor(s) on the technical table with the CARE replay system, and the referees not officiating seated at it (Article 3);
|
|
6
|
+
// and, for an event with no CARE system, two side judges with a majority of three (Article 13, 5). The Rules give no place for a side judge: the corners of the contest area are ours. The positions are the plan's own
|
|
7
|
+
// (`budoPlan`) and the figures round them in `judging.ts`, so that what is drawn and what is named cannot differ.
|
|
8
|
+
import { IJF_KATA } from "./leagues/budo.js";
|
|
9
|
+
/** How many officials a style seats at the most (a contest's two side judges included). */
|
|
10
|
+
export const JUDGING_SEAT_COUNT = Object.freeze({ kata: IJF_KATA.panel?.count ?? 5, shiai: 6 });
|
|
11
|
+
/** The seats of a kata area: five judges, the middle one the central judge. */
|
|
12
|
+
function kata() {
|
|
13
|
+
const count = IJF_KATA.panel?.count ?? 5;
|
|
14
|
+
const middle = Math.ceil(count / 2);
|
|
15
|
+
return Array.from({ length: count }, (_, i) => {
|
|
16
|
+
const n = i + 1;
|
|
17
|
+
const central = n === middle;
|
|
18
|
+
return { id: `judge-${n}`, n, role: central ? "central" : "judge", where: "table", label: { en: central ? `Judge ${n}, central` : `Judge ${n}`, ja: central ? `審判員${n}(中央)` : `審判員${n}` } };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** The seats of a contest: the referee, then the technical table's three, then the side judges (drawn only when asked for or named). */
|
|
22
|
+
function shiai() {
|
|
23
|
+
const seat = (n, id, role, where, en, ja, optional = false) => ({ id, n, role, where, label: { en, ja }, ...(optional ? { optional: true } : {}) });
|
|
24
|
+
return [
|
|
25
|
+
seat(1, "referee", "referee", "mat", "Referee", "主審"),
|
|
26
|
+
seat(2, "timekeeper", "timekeeper", "table", "Timekeeper", "計時係"),
|
|
27
|
+
seat(3, "scorekeeper", "scorekeeper", "table", "Scorekeeper", "記録係"),
|
|
28
|
+
seat(4, "supervisor", "supervisor", "table", "Referee supervisor", "審判委員"),
|
|
29
|
+
seat(5, "side-judge-1", "side-judge", "corner", "Side judge 1", "副審1", true),
|
|
30
|
+
seat(6, "side-judge-2", "side-judge", "corner", "Side judge 2", "副審2", true),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
/** The seats of every style, in the order they are listed. */
|
|
34
|
+
export const JUDGING_SEATS = Object.freeze({ kata: Object.freeze(kata()), shiai: Object.freeze(shiai()) });
|
|
35
|
+
/** The other words a seat is asked for by, besides its key and its number. */
|
|
36
|
+
export const JUDGING_SEAT_WORDS = Object.freeze({
|
|
37
|
+
"judge-3": ["central", "centre", "center"],
|
|
38
|
+
referee: ["main", "main-referee", "central-referee", "shimpan"],
|
|
39
|
+
timekeeper: ["time", "timer", "timing"],
|
|
40
|
+
scorekeeper: ["score", "scorer", "scoring", "recorder"],
|
|
41
|
+
supervisor: ["referee-supervisor", "jury", "care"],
|
|
42
|
+
"side-judge-1": ["judge-1", "side-1"],
|
|
43
|
+
"side-judge-2": ["judge-2", "side-2"],
|
|
44
|
+
});
|
|
45
|
+
/** The styles that can be asked for. */
|
|
46
|
+
export const JUDGING_STYLES = Object.freeze(["kata", "shiai"]);
|
|
47
|
+
/** The league each style is drawn in (`drawKyogijo`'s `league`), and the sources its seats are read from (keys of `LEAGUE_SOURCES`). */
|
|
48
|
+
export const JUDGING_LEAGUE = Object.freeze({
|
|
49
|
+
kata: { league: "ijf-kata", sources: ["ijf-sor", "ijf-kata-handbook", "ijf-kata-criteria"] },
|
|
50
|
+
shiai: { league: "ijf", sources: ["ijf-sor"] },
|
|
51
|
+
});
|
|
52
|
+
/** The most mat areas an assignment names: the plan's own limit for areas side by side. */
|
|
53
|
+
export const JUDGING_MATS_MAX = 6;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type JudgingSetting } from "./judging.ts";
|
|
2
|
+
import type { JudgingOptions } from "./judging.types.ts";
|
|
3
|
+
/** What a drawing of an assignment is, and what was worked out to make it. */
|
|
4
|
+
export interface JudgingDrawing {
|
|
5
|
+
svg: string;
|
|
6
|
+
/** The picture's width and height in its own units (its viewBox). */
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
/** Whether the chart is drawn. */
|
|
10
|
+
chart: boolean;
|
|
11
|
+
/** For every seat of every mat drawn: whether its name and ID are in the seat. A seat with nobody in it fits. */
|
|
12
|
+
cards: {
|
|
13
|
+
mat: number;
|
|
14
|
+
seat: string;
|
|
15
|
+
fits: boolean;
|
|
16
|
+
}[];
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
}
|
|
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
|
+
/** 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
|
+
export declare function judgingDrawing(options: JudgingOptions, mode?: "full" | "chart"): JudgingDrawing;
|
|
27
|
+
/**
|
|
28
|
+
* A judging assignment as one SVG string: for each mat, the judo area with a badge at each judge's seat and, where the name and ID fit in the seat, a card with both, and beside it the chart of seat, name and ID, whose rows
|
|
29
|
+
* grow to hold every name whole. `style` is the style the areas are judged in (`kata`: five judges); `mats` the mat areas, each with its `label` (`Mat 1`, `Mat 2` when missing) and its `officials`, each a `seat`, a `name`
|
|
30
|
+
* and an `id`. `mat` draws one mat alone (a tab); `chart` is `auto`, `always` or `never`; `focus: "bench"` shows the judges' bench close up so that the names in the seats are as large as they can be. Light and dark follow the
|
|
31
|
+
* page; `judgingTable` is the same thing as a table.
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { drawJudging } from "@johnmorrisdotca/kyogijo-stadiums/judging";
|
|
35
|
+
* const svg = drawJudging({
|
|
36
|
+
* style: "kata",
|
|
37
|
+
* mats: [{ label: "Mat 1", officials: [{ seat: 1, name: "Aiko Mori", id: "J-1042" }, { seat: "central", name: "Daniel Okafor", id: "J-0377" }] }],
|
|
38
|
+
* });
|
|
39
|
+
* console.log(svg.startsWith("<svg"), svg.includes("Aiko Mori"), svg.includes("J-1042"));
|
|
40
|
+
* // true true true
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function drawJudging(options: JudgingOptions): string;
|
|
44
|
+
/**
|
|
45
|
+
* The chart of an assignment alone: for each mat its seats in order, each with its number, its role, its name and, under the name, its ID, in rows that grow so that no name or ID is cut. For a page that draws
|
|
46
|
+
* the 3D view of the mat and puts the chart beside it.
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { judgingChart } from "@johnmorrisdotca/kyogijo-stadiums/judging";
|
|
50
|
+
* const svg = judgingChart({ style: "kata", mats: [{ officials: [{ seat: 1, name: "Aiko Mori", id: "J-1042" }] }] });
|
|
51
|
+
* console.log(svg.includes("ky-ju-chart-row"), svg.includes("Not assigned"));
|
|
52
|
+
* // true true
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function judgingChart(options: JudgingOptions): string;
|
|
56
|
+
/**
|
|
57
|
+
* The same thing as the picture, as a table: each mat, each seat and who sits in it, with the ID. For a reader who cannot see the drawing, and for a page that wants the data.
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { judgingTable } from "@johnmorrisdotca/kyogijo-stadiums/judging";
|
|
61
|
+
* const table = judgingTable({ style: "kata", mats: [{ officials: [{ seat: 3, name: "Daniel Okafor", id: "J-0377" }] }] });
|
|
62
|
+
* console.log(table.startsWith("<table"), table.includes("Daniel Okafor"));
|
|
63
|
+
* // true true
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function judgingTable(options: JudgingOptions): string;
|