@johnmorrisdotca/kyogijo-stadiums 0.18.1 → 0.20.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 +26 -0
- package/NOTICE.md +1 -0
- package/README.md +62 -28
- package/dist/budo/cage.d.ts +46 -0
- package/dist/budo/cage.js +91 -0
- package/dist/budo/describe.js +11 -0
- package/dist/budo/looks.js +8 -0
- package/dist/budo/plan.d.ts +10 -2
- package/dist/budo/plan.js +15 -1
- package/dist/budo/types.d.ts +11 -3
- package/dist/budo-entry.d.ts +1 -1
- package/dist/budo-entry.js +1 -1
- package/dist/budo.style.js +7 -2
- package/dist/common.d.ts +5 -0
- package/dist/common.js +6 -1
- package/dist/crowd.js +2 -0
- package/dist/draw.js +8 -7
- package/dist/features.js +10 -0
- package/dist/fields.types.d.ts +1 -1
- package/dist/heat.zones.js +1 -1
- package/dist/homeside.js +2 -0
- 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 +5 -0
- package/dist/judging.draw.d.ts +19 -6
- package/dist/judging.draw.js +14 -104
- package/dist/judging.js +14 -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.types.d.ts +9 -0
- package/dist/judging.words.d.ts +1 -0
- package/dist/judging.words.js +2 -0
- package/dist/leagues/budo.d.ts +3 -2
- package/dist/leagues/budo.js +2 -1
- package/dist/leagues/combat.d.ts +54 -0
- package/dist/leagues/combat.js +27 -0
- package/dist/leagues/sources.js +6 -0
- package/dist/leagues/types.d.ts +1 -1
- package/dist/leagues.d.ts +1 -0
- package/dist/leagues.js +21 -1
- package/dist/outline.js +1 -0
- package/dist/ranges.names.js +1 -0
- package/dist/score.js +3 -0
- package/dist/strings.d.ts +7 -1
- package/dist/strings.js +22 -10
- package/dist/surfaces/budo.js +3 -2
- package/dist/turn.kit.d.ts +1 -1
- package/dist/turn.style.js +8 -3
- package/dist/types.d.ts +4 -2
- package/dist/units.js +2 -0
- package/dist/uprights.budo.js +4 -2
- package/dist/uprights.cage.d.ts +4 -0
- package/dist/uprights.cage.js +91 -0
- package/dist/uprights.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -3
package/dist/budo/types.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** The sports of the budō family. */
|
|
2
|
-
export type BudoKind = "judo" | "karate" | "kendo" | "sumo" | "kyudo" | "dojo";
|
|
2
|
+
export type BudoKind = "judo" | "karate" | "kendo" | "sumo" | "kyudo" | "dojo" | CombatKind;
|
|
3
|
+
/** The combat sports the engine of the budō also draws: the MMA cage. */
|
|
4
|
+
export type CombatKind = "mma";
|
|
3
5
|
/** The sides of a hall, as a plan has them: north is the top of the drawing. `top`, `bottom`, `left` and `right` say the same. */
|
|
4
6
|
export type Compass = "north" | "south" | "east" | "west";
|
|
5
7
|
export type Side4 = Compass | "top" | "bottom" | "left" | "right";
|
|
@@ -19,7 +21,7 @@ export interface BudoStyle {
|
|
|
19
21
|
hall?: "budokan";
|
|
20
22
|
/** Judo: `shiai` (the contest area, the default) or `kata` (the IJF's kata area, `league: "ijf-kata"`: a centre tape, two white tapes 3 m from it either side, a safety area of 2 m; with `officials`, the five judges' seats on the shomen side and the coach's chair opposite). */
|
|
21
23
|
style?: "shiai" | "kata";
|
|
22
|
-
/** Judo: the contest area's side, 8 m to 10 m. Kendo: the shiai-jo's side, 9 m to 11 m. In metres. */
|
|
24
|
+
/** Judo: the contest area's side, 8 m to 10 m. Kendo: the shiai-jo's side, 9 m to 11 m. MMA cage: the width across the flats, 6.096 m to 9.754 m (20 to 32 feet), 9.144 m (30 feet) by default; 7.62 m is the smaller cage of 25 feet. In metres. */
|
|
23
25
|
size?: number;
|
|
24
26
|
/** Judo: the width of the safety area, 3 m or more (4 m by default). In metres. */
|
|
25
27
|
safety?: number;
|
|
@@ -37,12 +39,18 @@ export interface BudoStyle {
|
|
|
37
39
|
texture?: "weave" | "none";
|
|
38
40
|
/** Karate: the referee's and the judges' places. On by default. */
|
|
39
41
|
judges?: boolean;
|
|
40
|
-
/** Sumo: the height of the clay square in metres, 0.34 to 0.60. 0.55 by default. Seen in 3D. */
|
|
42
|
+
/** Sumo: the height of the clay square in metres, 0.34 to 0.60. 0.55 by default. MMA cage: the platform's height over the floor of the building, 0 to 1.219 m (4 feet), 1.219 m by default. Seen in 3D. */
|
|
41
43
|
height?: number;
|
|
42
44
|
/** Sumo: the four tassels of the roof, in the colours of the four quarters (green east, red south, white west, black north). Off by default. */
|
|
43
45
|
tassels?: boolean;
|
|
44
46
|
/** Sumo: the tawara, the shikiri-sen and the sand of the jano-me. On by default. */
|
|
45
47
|
tawara?: boolean;
|
|
48
|
+
/** MMA cage: the fence's height over the canvas, 1.524 m to 2.134 m (5 to 7 feet), 1.829 m (6 feet) by default. Seen in 3D. */
|
|
49
|
+
fence?: number;
|
|
50
|
+
/** MMA cage: the two gates, opposite each other (the fence is whole without them). On by default. */
|
|
51
|
+
gates?: boolean;
|
|
52
|
+
/** MMA cage: the steps up to the platform at each gate, three treads. On by default. */
|
|
53
|
+
steps?: boolean;
|
|
46
54
|
/** Kyūdō: the number of shooters in a line, 1 to 12 (5 by default). */
|
|
47
55
|
shooters?: number;
|
|
48
56
|
/** Kyūdō: the kind of range, `kinteki` (28 m, the default) or `enteki` (60 m); `league` says it too. */
|
package/dist/budo-entry.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { Dojo, Tatami } from "./budo/dojo.api.ts";
|
|
|
3
3
|
export { DOJO_SIZES, floorOf, shapeOfJo } from "./budo/dojo.ts";
|
|
4
4
|
export { dojoGallery, dojoRoom, ROOM_HEIGHTS } from "./budo/room.ts";
|
|
5
5
|
export type { DojoGallery, DojoRoom, RoomBalcony, RoomBasis, RoomOpening, RoomWall } from "./budo/room.ts";
|
|
6
|
-
export { budoLeague, budoPlan, BUDO_SPORTS, BUDOKAN_ARENA, isBudoSport } from "./budo/plan.ts";
|
|
6
|
+
export { budoLeague, budoPlan, BUDO_SPORTS, BUDOKAN_ARENA, COMBAT_SPORTS, isBudoSport, isCombatSport, isMatSport } from "./budo/plan.ts";
|
|
7
7
|
export type { BudoPlan, MBox, MMark, MRange } from "./budo/plan.ts";
|
|
8
8
|
export { checker, fourCorners, kindOf, lay, matCount, tint } from "./budo/tatami.ts";
|
|
9
9
|
export type { MatSize, Piece, PieceKind } from "./budo/tatami.ts";
|
package/dist/budo-entry.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export { DOJO_STANDARDS, dojo, drawDojo } from "./budo/dojo.api.js";
|
|
3
3
|
export { DOJO_SIZES, floorOf, shapeOfJo } from "./budo/dojo.js";
|
|
4
4
|
export { dojoGallery, dojoRoom, ROOM_HEIGHTS } from "./budo/room.js";
|
|
5
|
-
export { budoLeague, budoPlan, BUDO_SPORTS, BUDOKAN_ARENA, isBudoSport } from "./budo/plan.js";
|
|
5
|
+
export { budoLeague, budoPlan, BUDO_SPORTS, BUDOKAN_ARENA, COMBAT_SPORTS, isBudoSport, isCombatSport, isMatSport } from "./budo/plan.js";
|
|
6
6
|
export { checker, fourCorners, kindOf, lay, matCount, tint } from "./budo/tatami.js";
|
|
7
7
|
export { TATAMI } from "./budo/judo.js";
|
|
8
8
|
export { KIMARITE, KIMARITE_COUNT, KIMARITE_OTHERS, kimariteName, kimariteOf } from "./budo/kimarite.js";
|
package/dist/budo.style.js
CHANGED
|
@@ -37,6 +37,11 @@ const CLASSES = `
|
|
|
37
37
|
.kyogijo .ky-bud-tassel-s{fill:#d23b32;stroke:var(--ky-ink);stroke-opacity:.5;stroke-width:.03}
|
|
38
38
|
.kyogijo .ky-bud-tassel-w{fill:#f4f1e8;stroke:var(--ky-ink);stroke-opacity:.5;stroke-width:.03}
|
|
39
39
|
.kyogijo .ky-bud-tassel-n{fill:#232323;stroke:var(--ky-ink);stroke-opacity:.5;stroke-width:.03}`.trim();
|
|
40
|
+
/** The rules of the combat sports' classes, added to a combat drawing only, so that the budō drawings are the text they were: the steps up to a platform and the padding of a post. */
|
|
41
|
+
const COMBAT_CLASSES = `
|
|
42
|
+
.kyogijo .ky-bud-step{fill:color-mix(in srgb,var(--ky-bud-floor,#43484e) 76%,#fff);stroke:var(--ky-ink);stroke-opacity:.35;stroke-width:.03}
|
|
43
|
+
.kyogijo .ky-bud-pad{fill:var(--ky-ink);fill-opacity:.82}`.trim();
|
|
44
|
+
const COMBAT = ["mma"];
|
|
40
45
|
/** The custom properties of a look. */
|
|
41
46
|
const vars = (l) => `--ky-surface:${l.surface};--ky-surface-alt:${l.alt};--ky-red:${l.red};--ky-apron:${l.apron};--ky-free:${l.free};--ky-bud-floor:${l.floor};--ky-boards:${l.boards}${l.dirt === undefined ? "" : `;--ky-dirt:${l.dirt}`}${l.sand === undefined ? "" : `;--ky-sand:${l.sand}`}${l.straw === undefined ? "" : `;--ky-bud-straw:${l.straw}`}`;
|
|
42
47
|
/** The three rules of one look: light, dark by the device's setting, and dark by the page's `data-theme`. */
|
|
@@ -64,7 +69,7 @@ export function budoStyle(sport, look) {
|
|
|
64
69
|
const kind = sport;
|
|
65
70
|
if (BUDO_LOOKS[kind] === undefined)
|
|
66
71
|
return "";
|
|
67
|
-
return `${CLASSES}\n${look === undefined ? lookRules(kind, Object.keys(BUDO_LOOKS[kind])[0]) : lookRules(kind, look)}`;
|
|
72
|
+
return `${CLASSES}${COMBAT.includes(sport) ? `\n${COMBAT_CLASSES}` : ""}\n${look === undefined ? lookRules(kind, Object.keys(BUDO_LOOKS[kind])[0]) : lookRules(kind, look)}`;
|
|
68
73
|
}
|
|
69
74
|
/** Every budō sport's rules and every look, for a page that draws with `style: "none"` and supplies the stylesheet itself. */
|
|
70
|
-
export const KYOGIJO_BUDO_STYLE = `${CLASSES}${KYOGIJO_BUDO_GALLERY_STYLE}\n${Object.keys(BUDO_LOOKS).flatMap((sport) => Object.keys(BUDO_LOOKS[sport]).map((name) => lookRules(sport, name))).join("\n")}`;
|
|
75
|
+
export const KYOGIJO_BUDO_STYLE = `${CLASSES}\n${COMBAT_CLASSES}${KYOGIJO_BUDO_GALLERY_STYLE}\n${Object.keys(BUDO_LOOKS).flatMap((sport) => Object.keys(BUDO_LOOKS[sport]).map((name) => lookRules(sport, name))).join("\n")}`;
|
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/crowd.js
CHANGED
|
@@ -100,6 +100,8 @@ const PROFILES = {
|
|
|
100
100
|
sumo: { shape: "bowl", side: 58, end: 58, bench: 0, corner: 56, tiers: [{ id: "lower", from: 0, to: 54, height: [1, 8], fill: 1 }, upper(62, 128, 26, 62)], away: "corner" },
|
|
101
101
|
kyudo: { shape: "sides", side: 10, end: 8, bench: 0, corner: 6, tiers: [lower(24, 2, 8), upper(30, 52, 12, 22)], away: "corner" },
|
|
102
102
|
dojo: { shape: "bowl", side: 5, end: 5, bench: 0, corner: 8, tiers: [lower(26, 2, 14), upper(32, 58, 20, 36)], away: "corner" },
|
|
103
|
+
// An MMA cage stands in the middle of an arena, with the seats rising from the ring of the floor.
|
|
104
|
+
mma: { shape: "bowl", side: 40, end: 40, bench: 0, corner: 56, tiers: [lower(60, 3, 24), upper(67, 120, 32, 60)], away: "corner" },
|
|
103
105
|
};
|
|
104
106
|
/** The grounds of the package that are the home of an NFL or a CFL club, where a soccer pitch stands inside a gridiron's stands. From each ground's article. */
|
|
105
107
|
export const GRIDIRON_GROUNDS = Object.freeze({
|
package/dist/draw.js
CHANGED
|
@@ -17,7 +17,7 @@ import { athleticsPlan } from "./athletics/plan.js";
|
|
|
17
17
|
import { skatingPlan } from "./skating/plan.js";
|
|
18
18
|
import { skatingAbout, skatingSentences } from "./skating/describe.js";
|
|
19
19
|
import { skatingStyle } from "./skating.style.js";
|
|
20
|
-
import { budoPlan, isBudoSport } from "./budo/plan.js";
|
|
20
|
+
import { budoPlan, isBudoSport, isMatSport } from "./budo/plan.js";
|
|
21
21
|
import { dojoSpecOf } from "./budo/dojo.js";
|
|
22
22
|
import { dojoGallery } from "./budo/room.js";
|
|
23
23
|
import { budoAbout, budoScoreSentences, budoSentences } from "./budo/describe.js";
|
|
@@ -91,7 +91,7 @@ import { abbreviate, capitals } from "./text.js";
|
|
|
91
91
|
import { VERSION } from "./version.js";
|
|
92
92
|
export { isPortrait };
|
|
93
93
|
/** The sports that can be drawn, in the order a menu lists them. */
|
|
94
|
-
export const SPORTS = ["nfl", "cfl", "ifaf", "nhl", "nba", "mlb", "soccer", "curling", "tennis", "volleyball", "badminton", "pickleball", "tabletennis", "padel", "squash", "racquetball", "sepaktakraw", "teqball", "roundnet", "netball", "swimming", "waterpolo", "diving", "artisticswimming", "athletics", "skating", "judo", "karate", "kendo", "sumo", "kyudo", "dojo", "lacrosse", "rugby", "afl", "gaelic", "cricket", "fieldhockey", "handball"];
|
|
94
|
+
export const SPORTS = ["nfl", "cfl", "ifaf", "nhl", "nba", "mlb", "soccer", "curling", "tennis", "volleyball", "badminton", "pickleball", "tabletennis", "padel", "squash", "racquetball", "sepaktakraw", "teqball", "roundnet", "netball", "swimming", "waterpolo", "diving", "artisticswimming", "athletics", "skating", "judo", "karate", "kendo", "sumo", "kyudo", "dojo", "mma", "lacrosse", "rugby", "afl", "gaelic", "cricket", "fieldhockey", "handball"];
|
|
95
95
|
/** The CSS custom property each colour of `Colors` sets. */
|
|
96
96
|
export const COLOR_PROPERTIES = {
|
|
97
97
|
apron: "--ky-apron",
|
|
@@ -265,7 +265,7 @@ function buildSkating(o, common) {
|
|
|
265
265
|
/** The budō surface: its plan, drawn as it lies. A hall, a kyūdōjō and a range of mats have little ground round them. */
|
|
266
266
|
function buildBudo(o, common) {
|
|
267
267
|
const plan = budoPlan({ ...o, detail: common.detail });
|
|
268
|
-
return budoSurface(common, plan, common.margin ?? (o.range === undefined ? 12 : 4));
|
|
268
|
+
return budoSurface(common, plan, common.margin ?? (o.range === undefined ? (plan.mma === undefined ? 12 : 5) : 4));
|
|
269
269
|
}
|
|
270
270
|
/** One text for both ends or sides, or a pair of them. */
|
|
271
271
|
const pair = (text) => (text === undefined ? undefined : typeof text === "string" ? [text, text] : text);
|
|
@@ -373,6 +373,7 @@ function buildWhole(o, portrait, id, score, scored, extra) {
|
|
|
373
373
|
case "sumo":
|
|
374
374
|
case "kyudo":
|
|
375
375
|
case "dojo":
|
|
376
|
+
case "mma":
|
|
376
377
|
return buildBudo({ ...o, sport }, common);
|
|
377
378
|
default:
|
|
378
379
|
throw new Error(`Unknown sport "${String(o.sport)}": use one of ${SPORTS.join(", ")}`);
|
|
@@ -608,7 +609,7 @@ function leagueAbout(league, year, language, sheet) {
|
|
|
608
609
|
const words = KYOGIJO_STRINGS[language].league;
|
|
609
610
|
if (league.family === "skating")
|
|
610
611
|
return skatingAbout({ sport: "skating", league: league.id }, language);
|
|
611
|
-
if (league.family === "judo" || league.family === "karate" || league.family === "kendo" || league.family === "sumo" || league.family === "kyudo" || league.family === "dojo")
|
|
612
|
+
if (league.family === "judo" || league.family === "karate" || league.family === "kendo" || league.family === "sumo" || league.family === "kyudo" || league.family === "dojo" || league.family === "mma")
|
|
612
613
|
return budoAbout({ sport: league.family, league: league.id }, language);
|
|
613
614
|
if (league.family === "athletics")
|
|
614
615
|
return athleticsAbout({ sport: "athletics", league: league.id, athletics: sheet === undefined ? undefined : undefined }, language);
|
|
@@ -697,8 +698,8 @@ export function describe(o) {
|
|
|
697
698
|
const poolLine = pools === undefined ? "" : pools.after.map((line) => `${gap}${line}`).join("");
|
|
698
699
|
// An arena of a size of its own says what it is at that size.
|
|
699
700
|
const arenaAbout = arenaSize === undefined ? undefined : fill(sport === "nhl" ? words.said.arenaRinkAbout : words.said.arenaCourtAbout, { length: metres(arenaSize.length), width: metres(arenaSize.width), lengthM: metres(arenaSize.length * 0.3048), widthM: metres(arenaSize.width * 0.3048) });
|
|
700
|
-
const aboutText = arenaAbout !== undefined ? arenaAbout : pools !== undefined ? pools.about :
|
|
701
|
-
const about = `${words.said.on}${colon}${aboutText}${stop}${sport === "athletics" ? athleticsSentences(o, language) : sport === "skating" ? skatingSentences(o, language) :
|
|
701
|
+
const aboutText = arenaAbout !== undefined ? arenaAbout : pools !== undefined ? pools.about : isMatSport(sport) ? budoAbout(o, language) : sport === "skating" ? skatingAbout(o, language) : sport === "athletics" ? athleticsAbout(o, language) : field !== undefined ? leagueAbout(league ?? LEAGUES[sport][0], o.year, language, { length: field.length, width: field.width }) : plan !== undefined ? leagueAbout(plan.league, o.year, language, plan.spec) : league !== undefined ? leagueAbout(league, o.year, language) : pitch === undefined ? words.about[sport] : fill(pitch.format === "futsal" ? words.soccer.aboutFutsal : words.about.soccer, { length: metres(pitch.length), width: metres(pitch.width) });
|
|
702
|
+
const about = `${words.said.on}${colon}${aboutText}${stop}${sport === "athletics" ? athleticsSentences(o, language) : sport === "skating" ? skatingSentences(o, language) : isMatSport(sport) ? budoSentences(o, language) : ""}`;
|
|
702
703
|
const halfLine = pitch !== undefined && !isScore(o) && (o.half === "left" || o.half === "right") ? `${gap}${words.soccer.half}` : "";
|
|
703
704
|
// What the ground says about the size: that it is the published one, or that the ground has none and the international pitch is drawn.
|
|
704
705
|
const year = typeof o.year === "number" && Number.isFinite(o.year) ? o.year : undefined;
|
|
@@ -889,7 +890,7 @@ function drawnKyogijo(o) {
|
|
|
889
890
|
const crowded = crowdOf(o) !== undefined;
|
|
890
891
|
const style = colourStyle(o, { left: leftTeam, right: rightTeam, home: isScore(o) ? o.home : undefined, away: isScore(o) ? o.away : undefined }, featured);
|
|
891
892
|
const palette = isLook(o.look) ? o.look : undefined;
|
|
892
|
-
const budoLook =
|
|
893
|
+
const budoLook = isMatSport(sport) ? budoLookOf(sport, o.budo?.look ?? (sport === "dojo" ? dojoSpecOf(o.dojo).look : undefined)) : undefined;
|
|
893
894
|
let notes;
|
|
894
895
|
const theme = o.theme === "light" || o.theme === "dark" ? o.theme : undefined;
|
|
895
896
|
let viewBox;
|
package/dist/features.js
CHANGED
|
@@ -128,6 +128,15 @@ const SUMO = [
|
|
|
128
128
|
f("tawara", "--ky-bud-straw", "The tawara of the ring."),
|
|
129
129
|
f("shikiri-sen", "--ky-line", "The two shikiri-sen."),
|
|
130
130
|
];
|
|
131
|
+
const MMA = [
|
|
132
|
+
f("apron", "--ky-apron", "The floor of the hall round the platform."),
|
|
133
|
+
f("platform", "--ky-bud-floor", "The platform the cage stands on."),
|
|
134
|
+
f("steps", "--ky-bud-floor", "The steps up to the platform."),
|
|
135
|
+
f("canvas", "--ky-surface", "The canvas inside the fence."),
|
|
136
|
+
f("fence", "--ky-ink", "The fence, one line on each flat."),
|
|
137
|
+
f("gates", "--ky-ink", "The swing of the two gates."),
|
|
138
|
+
f("posts", "--ky-ink", "The eight padded posts."),
|
|
139
|
+
];
|
|
131
140
|
const KYUDO = [
|
|
132
141
|
f("apron", "--ky-apron", "The ground round the range."),
|
|
133
142
|
f("shajo", "--ky-bud-floor", "The floor of the shajō."),
|
|
@@ -435,6 +444,7 @@ export const FEATURE_INFO = Object.freeze({
|
|
|
435
444
|
sumo: SUMO,
|
|
436
445
|
kyudo: KYUDO,
|
|
437
446
|
dojo: DOJO,
|
|
447
|
+
mma: MMA,
|
|
438
448
|
});
|
|
439
449
|
/**
|
|
440
450
|
* The names of the features of each sport: the keys `featureColors` takes. Football's three fields have the same, and so have the five net sports.
|
package/dist/fields.types.d.ts
CHANGED
|
@@ -95,7 +95,7 @@ export type Shape = LineShape | ArcShape | RingShape | BoxShape | PolyShape | Do
|
|
|
95
95
|
/** The areas of a skating rink: the ice, the floor of the infield, the warm-up lane, the padding and the furniture. */
|
|
96
96
|
export type SkatingArea = "ky-ska-ice" | "ky-ska-floor" | "ky-ska-warm" | "ky-ska-pad" | "ky-ska-desk" | "ky-ska-kiss";
|
|
97
97
|
/** The areas of a budō surface: the mats in three tones, the heri of a mat, the floor, the walls, the platform and the furniture, the clay and the sand and the straw of a dohyō, the azuchi and the yamichi. */
|
|
98
|
-
export type BudoArea = "ky-bud-t1" | "ky-bud-t2" | "ky-bud-t3" | "ky-bud-heri" | "ky-bud-floor" | "ky-bud-wall" | "ky-bud-window" | "ky-bud-door" | "ky-bud-platform" | "ky-bud-free" | "ky-bud-desk" | "ky-bud-clay" | "ky-bud-sand" | "ky-bud-tawara" | "ky-bud-azuchi" | "ky-bud-roof" | "ky-bud-yamichi" | "ky-bud-shrine" | "ky-bud-dais" | "ky-bud-banner" | "ky-bud-lane" | "ky-bud-mato" | "ky-bud-tassel-e" | "ky-bud-tassel-s" | "ky-bud-tassel-w" | "ky-bud-tassel-n" | "ky-bud-seat";
|
|
98
|
+
export type BudoArea = "ky-bud-t1" | "ky-bud-t2" | "ky-bud-t3" | "ky-bud-heri" | "ky-bud-floor" | "ky-bud-wall" | "ky-bud-window" | "ky-bud-door" | "ky-bud-platform" | "ky-bud-free" | "ky-bud-desk" | "ky-bud-clay" | "ky-bud-sand" | "ky-bud-tawara" | "ky-bud-azuchi" | "ky-bud-roof" | "ky-bud-yamichi" | "ky-bud-shrine" | "ky-bud-dais" | "ky-bud-banner" | "ky-bud-lane" | "ky-bud-mato" | "ky-bud-tassel-e" | "ky-bud-tassel-s" | "ky-bud-tassel-w" | "ky-bud-tassel-n" | "ky-bud-seat" | "ky-bud-step" | "ky-bud-pad";
|
|
99
99
|
export type AthleticsArea = "ky-ath-track" | "ky-ath-grass" | "ky-ath-sand" | "ky-ath-mat" | "ky-ath-water" | "ky-ath-concrete" | "ky-ath-pad" | "ky-ath-board" | "ky-ath-bank";
|
|
100
100
|
/** A painted area, under the lines: a rectangle or an ellipse filled with a class of the stylesheet (`ky-area`, the tint of a goal area, or `ky-zone`). */
|
|
101
101
|
export interface Area extends Named {
|
package/dist/heat.zones.js
CHANGED
|
@@ -37,7 +37,7 @@ export const ZONE_SETS = Object.freeze({
|
|
|
37
37
|
"pool-lanes": { sports: ["swimming"], title: "Lanes: each lane of the pool, the whole length of it", source: "docs/sources.md#zone-sets" },
|
|
38
38
|
"water-polo-areas": { sports: ["waterpolo"], title: "The goal area, the ground from 2 to 6 m, and the rest of the field, at each end", source: "docs/sources.md#zone-sets" },
|
|
39
39
|
"pool-thirds": { sports: ["diving", "artisticswimming"], title: "Thirds along the pool, from the wall the boards or the judges stand at", source: "docs/sources.md#zone-sets" },
|
|
40
|
-
"budo-areas": { sports: ["judo", "karate", "kendo", "sumo", "kyudo", "dojo"], title: "The surface in its areas: the contest and the safety areas, the boundary band, the clay and the ring of a dohyō, the shajō, the yamichi and the azuchi, a dojo's floor", source: "docs/sources.md#zone-sets" },
|
|
40
|
+
"budo-areas": { sports: ["judo", "karate", "kendo", "sumo", "kyudo", "dojo", "mma"], title: "The surface in its areas: the contest and the safety areas, the boundary band, the clay and the ring of a dohyō, the shajō, the yamichi and the azuchi, a dojo's floor", source: "docs/sources.md#zone-sets" },
|
|
41
41
|
"field-thirds": { sports: ["lacrosse", "rugby", "afl", "gaelic", "fieldhockey", "handball", "netball"], title: "Thirds: defensive, middle and attacking", source: "docs/sources.md#zone-sets" },
|
|
42
42
|
"skating-track": { sports: ["skating"], title: "The rink in parts: the finish straight, the first curve, the crossing straight, the second curve and the infield (a figure skating rink in thirds)", source: "docs/sources.md#zone-sets" },
|
|
43
43
|
"athletics-track": { sports: ["athletics"], title: "The track in parts: the finish straight, the first bend, the back straight, the second bend, and the infield", source: "docs/sources.md#zone-sets" },
|
package/dist/homeside.js
CHANGED
|
@@ -49,6 +49,8 @@ export const HOME_FIRST = Object.freeze({
|
|
|
49
49
|
sumo: false,
|
|
50
50
|
kyudo: false,
|
|
51
51
|
dojo: false,
|
|
52
|
+
// A cage fight is between a red corner and a blue corner: no home side.
|
|
53
|
+
mma: false,
|
|
52
54
|
});
|
|
53
55
|
/** The leagues whose convention is not their sport's: the international federation's lacrosse lists the home team first. */
|
|
54
56
|
export const HOME_FIRST_LEAGUES = Object.freeze({
|
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,6 +28,8 @@ 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;
|
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
|
/**
|