@johnmorrisdotca/kyogijo-stadiums 0.4.0 → 0.5.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 +75 -0
- package/NOTICE.md +4 -0
- package/README.md +71 -16
- package/dist/annotate.js +1 -1
- package/dist/athletics/describe.d.ts +8 -0
- package/dist/athletics/describe.js +41 -0
- package/dist/athletics/events.d.ts +17 -0
- package/dist/athletics/events.js +48 -0
- package/dist/athletics/facilities.d.ts +80 -0
- package/dist/athletics/facilities.js +176 -0
- package/dist/athletics/infield.d.ts +79 -0
- package/dist/athletics/infield.js +166 -0
- package/dist/athletics/layout.d.ts +13 -0
- package/dist/athletics/layout.js +98 -0
- package/dist/athletics/oval.d.ts +57 -0
- package/dist/athletics/oval.js +116 -0
- package/dist/athletics/plan.d.ts +97 -0
- package/dist/athletics/plan.js +355 -0
- package/dist/athletics/races.d.ts +102 -0
- package/dist/athletics/races.js +355 -0
- package/dist/athletics/steeplechase.d.ts +72 -0
- package/dist/athletics/steeplechase.js +196 -0
- package/dist/athletics/stencil.d.ts +13 -0
- package/dist/athletics/stencil.js +85 -0
- package/dist/athletics/track.d.ts +54 -0
- package/dist/athletics/track.js +105 -0
- package/dist/athletics/types.d.ts +77 -0
- package/dist/athletics/types.js +1 -0
- package/dist/athletics-entry.d.ts +17 -0
- package/dist/athletics-entry.js +11 -0
- package/dist/athletics.style.d.ts +16 -0
- package/dist/athletics.style.js +51 -0
- package/dist/atlas-entry.d.ts +4 -2
- package/dist/atlas-entry.js +3 -2
- package/dist/atlas.d.ts +83 -7
- package/dist/atlas.js +108 -8
- package/dist/charts-entry.d.ts +6 -1
- package/dist/charts-entry.js +3 -0
- package/dist/charts.athletics.d.ts +183 -0
- package/dist/charts.athletics.js +455 -0
- package/dist/charts.curling.heat.d.ts +24 -0
- package/dist/charts.curling.heat.js +116 -0
- package/dist/charts.curling.js +14 -3
- package/dist/charts.pool.d.ts +67 -0
- package/dist/charts.pool.js +76 -0
- package/dist/charts.skating.d.ts +204 -0
- package/dist/charts.skating.js +426 -0
- package/dist/charts.types.d.ts +53 -1
- package/dist/court.d.ts +85 -2
- package/dist/court.js +102 -7
- package/dist/court.more.d.ts +46 -0
- package/dist/court.more.js +219 -0
- package/dist/courts.style.d.ts +14 -2
- package/dist/courts.style.js +51 -4
- package/dist/crowd.d.ts +154 -0
- package/dist/crowd.draw.d.ts +17 -0
- package/dist/crowd.draw.js +198 -0
- package/dist/crowd.js +465 -0
- package/dist/crowd.park.d.ts +19 -0
- package/dist/crowd.park.js +153 -0
- package/dist/curling.stats.d.ts +271 -0
- package/dist/curling.stats.js +301 -0
- package/dist/draw.d.ts +16 -0
- package/dist/draw.js +318 -35
- package/dist/element-entry.d.ts +1 -1
- package/dist/element-entry.js +1 -1
- package/dist/element.d.ts +13 -2
- package/dist/element.js +77 -3
- package/dist/features.js +131 -0
- package/dist/fields.kit.d.ts +2 -2
- package/dist/fields.types.d.ts +18 -4
- package/dist/frames.providers.js +63 -8
- package/dist/geojson.js +3 -0
- package/dist/geometry-entry.d.ts +2 -1
- package/dist/geometry-entry.js +2 -1
- package/dist/geometry.d.ts +20 -0
- package/dist/geometry.js +78 -1
- package/dist/grounds.d.ts +4 -0
- package/dist/grounds.data.js +12 -0
- package/dist/hardwood.d.ts +31 -0
- package/dist/hardwood.js +157 -0
- package/dist/heat.js +4 -3
- package/dist/heat.types.d.ts +5 -0
- package/dist/heat.zones.d.ts +2 -2
- package/dist/heat.zones.js +154 -6
- package/dist/homeside.js +17 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +10 -1
- package/dist/layers.d.ts +1 -1
- package/dist/layers.env.d.ts +3 -1
- package/dist/layers.env.js +4 -2
- package/dist/layers.js +4 -4
- package/dist/leagues/athletics.d.ts +63 -0
- package/dist/leagues/athletics.js +87 -0
- package/dist/leagues/courts.d.ts +269 -4
- package/dist/leagues/courts.js +155 -1
- package/dist/leagues/skating.d.ts +145 -0
- package/dist/leagues/skating.js +73 -0
- package/dist/leagues/sources.js +20 -0
- package/dist/leagues/types.d.ts +1 -1
- package/dist/leagues-entry.d.ts +4 -2
- package/dist/leagues-entry.js +2 -1
- package/dist/leagues.d.ts +14 -4
- package/dist/leagues.js +146 -5
- package/dist/look.d.ts +3 -3
- package/dist/look.js +39 -6
- package/dist/outline.d.ts +1 -1
- package/dist/outline.js +30 -2
- package/dist/pageant.d.ts +120 -0
- package/dist/pageant.draw.d.ts +21 -0
- package/dist/pageant.draw.js +171 -0
- package/dist/pageant.js +207 -0
- package/dist/pageant.style.d.ts +8 -0
- package/dist/pageant.style.js +42 -0
- package/dist/png.d.ts +8 -1
- package/dist/png.js +21 -1
- package/dist/pool.d.ts +176 -0
- package/dist/pool.figures.d.ts +304 -0
- package/dist/pool.figures.js +144 -0
- package/dist/pool.js +304 -0
- package/dist/pool.kit.d.ts +48 -0
- package/dist/pool.kit.js +141 -0
- package/dist/pool.labels.d.ts +20 -0
- package/dist/pool.labels.js +257 -0
- package/dist/pool.race.d.ts +65 -0
- package/dist/pool.race.js +140 -0
- package/dist/pool.replay.d.ts +46 -0
- package/dist/pool.replay.js +127 -0
- package/dist/pool.section.d.ts +13 -0
- package/dist/pool.section.js +83 -0
- package/dist/pool.style.d.ts +20 -0
- package/dist/pool.style.js +169 -0
- package/dist/pool.types.d.ts +145 -0
- package/dist/pool.types.js +3 -0
- package/dist/pool.words.d.ts +13 -0
- package/dist/pool.words.js +101 -0
- package/dist/ranges.names.js +47 -3
- package/dist/replay-entry.d.ts +3 -0
- package/dist/replay-entry.js +2 -0
- package/dist/restyle.js +1 -1
- package/dist/score.js +70 -5
- package/dist/sheet.d.ts +3 -0
- package/dist/sheet.js +7 -3
- package/dist/skating/describe.d.ts +7 -0
- package/dist/skating/describe.js +44 -0
- package/dist/skating/events.d.ts +24 -0
- package/dist/skating/events.js +47 -0
- package/dist/skating/figure.d.ts +24 -0
- package/dist/skating/figure.js +37 -0
- package/dist/skating/long.d.ts +54 -0
- package/dist/skating/long.js +111 -0
- package/dist/skating/parts.d.ts +43 -0
- package/dist/skating/parts.js +40 -0
- package/dist/skating/plan.d.ts +55 -0
- package/dist/skating/plan.js +197 -0
- package/dist/skating/short.d.ts +47 -0
- package/dist/skating/short.js +89 -0
- package/dist/skating/track.d.ts +66 -0
- package/dist/skating/track.js +94 -0
- package/dist/skating/types.d.ts +57 -0
- package/dist/skating/types.js +3 -0
- package/dist/skating-entry.d.ts +17 -0
- package/dist/skating-entry.js +11 -0
- package/dist/skating.style.d.ts +4 -0
- package/dist/skating.style.js +24 -0
- package/dist/strings.d.ts +296 -0
- package/dist/strings.js +328 -11
- package/dist/style.d.ts +2 -0
- package/dist/style.js +11 -1
- package/dist/surfaces/artistic.d.ts +9 -0
- package/dist/surfaces/artistic.js +94 -0
- package/dist/surfaces/athletics.d.ts +16 -0
- package/dist/surfaces/athletics.js +132 -0
- package/dist/surfaces/baseball.js +15 -0
- package/dist/surfaces/basketball.floor.d.ts +27 -0
- package/dist/surfaces/basketball.floor.js +83 -0
- package/dist/surfaces/basketball.gear.d.ts +27 -0
- package/dist/surfaces/basketball.gear.js +90 -0
- package/dist/surfaces/basketball.js +43 -21
- package/dist/surfaces/curling.d.ts +16 -0
- package/dist/surfaces/curling.fold.d.ts +67 -0
- package/dist/surfaces/curling.fold.js +107 -0
- package/dist/surfaces/curling.js +37 -3
- package/dist/surfaces/dive.d.ts +9 -0
- package/dist/surfaces/dive.js +128 -0
- package/dist/surfaces/field.d.ts +7 -2
- package/dist/surfaces/field.js +15 -9
- package/dist/surfaces/hockey.js +1 -0
- package/dist/surfaces/net.d.ts +2 -1
- package/dist/surfaces/net.js +160 -15
- package/dist/surfaces/polo.d.ts +12 -0
- package/dist/surfaces/polo.js +159 -0
- package/dist/surfaces/pool.d.ts +27 -0
- package/dist/surfaces/pool.js +198 -0
- package/dist/surfaces/skating.d.ts +6 -0
- package/dist/surfaces/skating.js +62 -0
- package/dist/surfaces/soccer.js +2 -1
- package/dist/surfaces/surface.d.ts +44 -0
- package/dist/surfaces/venue.d.ts +15 -0
- package/dist/surfaces/venue.js +95 -0
- package/dist/tenants.d.ts +77 -0
- package/dist/tenants.data.d.ts +8 -0
- package/dist/tenants.data.js +945 -0
- package/dist/tenants.js +46 -0
- package/dist/turn-entry.d.ts +12 -0
- package/dist/turn-entry.js +7 -0
- package/dist/turn.camera.d.ts +105 -0
- package/dist/turn.camera.js +168 -0
- package/dist/turn.dom.d.ts +40 -0
- package/dist/turn.dom.js +351 -0
- package/dist/turn.kit.d.ts +86 -0
- package/dist/turn.kit.js +110 -0
- package/dist/turn.markup.d.ts +48 -0
- package/dist/turn.markup.js +108 -0
- package/dist/turn.model.d.ts +78 -0
- package/dist/turn.model.js +91 -0
- package/dist/turn.style.d.ts +5 -0
- package/dist/turn.style.js +55 -0
- package/dist/types.d.ts +183 -18
- package/dist/units.d.ts +1 -1
- package/dist/units.js +15 -1
- package/dist/uprights.board.d.ts +17 -0
- package/dist/uprights.board.js +59 -0
- package/dist/uprights.d.ts +37 -0
- package/dist/uprights.fields.d.ts +32 -0
- package/dist/uprights.fields.js +172 -0
- package/dist/uprights.goal.d.ts +49 -0
- package/dist/uprights.goal.js +69 -0
- package/dist/uprights.js +160 -0
- package/dist/uprights.more.d.ts +7 -0
- package/dist/uprights.more.js +183 -0
- package/dist/uprights.net.d.ts +12 -0
- package/dist/uprights.net.js +109 -0
- package/dist/uprights.netkit.d.ts +28 -0
- package/dist/uprights.netkit.js +67 -0
- package/dist/uprights.pools.d.ts +8 -0
- package/dist/uprights.pools.js +190 -0
- package/dist/uprights.rinks.d.ts +27 -0
- package/dist/uprights.rinks.js +106 -0
- package/dist/uprights.track.d.ts +50 -0
- package/dist/uprights.track.js +246 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +19 -2
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// A side section of a swimming pool, drawn under its plan on the same scale along the pool: the water and its depth, the starting blocks and touch panels at the walls, the backstroke flags 5 m from each end, the
|
|
2
|
+
// false start rope 15 m from the starting end, a lane rope at the surface, and the least depth the rules ask for (1.35 m from 1 to 6 m from a wall with blocks, then the pool's own). Its height is exaggerated
|
|
3
|
+
// (`section.exaggerate`, 2.5 by default): a pool 50 m long and 2.5 m deep would be a sliver otherwise. Written in feet; the words are upright whatever the pool does.
|
|
4
|
+
import { el, num } from "./format.js";
|
|
5
|
+
import { feet } from "./pool.js";
|
|
6
|
+
import { SWIMMING } from "./pool.figures.js";
|
|
7
|
+
import { textOn, ft } from "./surfaces/surface.js";
|
|
8
|
+
/**
|
|
9
|
+
* The section of a pool whose water's surface is at `top` feet (in the drawing's frame, below the plan), for a pool that is `plan.length` long, aligned with the plan along x.
|
|
10
|
+
*/
|
|
11
|
+
export function sectionOf(plan, o, top) {
|
|
12
|
+
const sec = plan.section;
|
|
13
|
+
if (sec === undefined)
|
|
14
|
+
return { markup: "", height: 0, defs: "" };
|
|
15
|
+
const E = sec.exaggerate;
|
|
16
|
+
const L = feet(plan.length);
|
|
17
|
+
const v = (metres) => feet(metres) * E;
|
|
18
|
+
const depth = plan.depth;
|
|
19
|
+
const surfaceY = top + v(SWIMMING.flags.height) + 4;
|
|
20
|
+
const floorY = surfaceY + v(depth);
|
|
21
|
+
const full = o.detail === "full";
|
|
22
|
+
const turned = o.portrait;
|
|
23
|
+
const gradient = `${o.id}-wd`;
|
|
24
|
+
let out = "";
|
|
25
|
+
const defs = plan.look === "flat" ? "" : el("linearGradient", { id: gradient, x1: 0, y1: 0, x2: 0, y2: 1 }, el("stop", { offset: 0, class: "ky-pl-sa" }) + el("stop", { offset: 1, class: "ky-pl-sc" }));
|
|
26
|
+
// The ground under the section is the deck's colour; the water body between the walls.
|
|
27
|
+
out += el("rect", { class: ft(o, "water", "ky-surface"), x: 0, y: surfaceY, width: L, height: floorY - surfaceY });
|
|
28
|
+
if (plan.look !== "flat")
|
|
29
|
+
out += el("rect", { class: "ky-pl-wg", x: 0, y: surfaceY, width: L, height: floorY - surfaceY, fill: `url(#${gradient})` });
|
|
30
|
+
// The walls and the floor of the pool as a section: a thick line, with the deck level at the surface.
|
|
31
|
+
const wall = 1.1;
|
|
32
|
+
out += el("path", { class: ft(o, "gutter", "ky-pl-sw"), d: `M${num(-wall)} ${num(surfaceY - 0.6)}H0V${num(floorY)}H${num(L)}V${num(surfaceY - 0.6)}H${num(L + wall)}V${num(floorY + wall)}H${num(-wall)}Z` });
|
|
33
|
+
// The least depth the rules ask for.
|
|
34
|
+
const least = feet(SWIMMING.depth.atBlocks) * E;
|
|
35
|
+
const blocksFrom = feet(SWIMMING.depth.blocksFrom);
|
|
36
|
+
const blocksTo = feet(SWIMMING.depth.blocksTo);
|
|
37
|
+
if (full) {
|
|
38
|
+
const y = surfaceY + least;
|
|
39
|
+
const d = `M${num(blocksFrom)} ${num(y)}H${num(blocksTo)}M${num(L - blocksTo)} ${num(y)}H${num(L - blocksFrom)}`;
|
|
40
|
+
out += el("path", { class: "ky-line ky-pl-lm", d, "stroke-width": 0.35, "stroke-dasharray": "1.4 1", fill: "none" });
|
|
41
|
+
out += textOn(turned, (blocksFrom + blocksTo) / 2, y - 0.9, `${SWIMMING.depth.atBlocks} m`, { size: 2, anchor: "middle", cls: "ky-pl-sx" });
|
|
42
|
+
}
|
|
43
|
+
// Blocks (0.5 to 0.75 m above the water) and touch panels (0.3 m above, 0.6 m below).
|
|
44
|
+
const blockH = v(SWIMMING.block.height);
|
|
45
|
+
const blockL = feet(SWIMMING.block.length) * 1.4;
|
|
46
|
+
if (plan.blocks) {
|
|
47
|
+
out += el("path", { class: "ky-pl-bk", d: `M${num(-blockL)} ${num(surfaceY)}V${num(surfaceY - blockH)}H${num(-blockL * 0.15)}L0 ${num(surfaceY - blockH * 0.8)}V${num(surfaceY)}ZM${num(L + blockL)} ${num(surfaceY)}V${num(surfaceY - blockH)}H${num(L + blockL * 0.15)}L${num(L)} ${num(surfaceY - blockH * 0.8)}V${num(surfaceY)}Z` });
|
|
48
|
+
}
|
|
49
|
+
if (plan.pads) {
|
|
50
|
+
const above = v(SWIMMING.pad.above);
|
|
51
|
+
const below = v(SWIMMING.pad.below);
|
|
52
|
+
const w = 0.9;
|
|
53
|
+
out += el("path", { class: "ky-pl-pad", d: `M0 ${num(surfaceY - above)}h${num(w)}V${num(surfaceY + below)}H0ZM${num(L)} ${num(surfaceY - above)}h${num(-w)}V${num(surfaceY + below)}H${num(L)}Z`, stroke: "none" });
|
|
54
|
+
}
|
|
55
|
+
// The backstroke flags: a rope 1.8 m up between two standards, with its flags, 5 m from each wall.
|
|
56
|
+
if (plan.flags) {
|
|
57
|
+
for (const x of [SWIMMING.flags.at, plan.length - SWIMMING.flags.at]) {
|
|
58
|
+
const px = feet(x);
|
|
59
|
+
const h = v(SWIMMING.flags.height);
|
|
60
|
+
out += el("path", { class: "ky-line ky-pl-pole", d: `M${num(px)} ${num(surfaceY)}V${num(surfaceY - h)}`, "stroke-width": 0.4, fill: "none" });
|
|
61
|
+
// Seen along the pool the rope is a point, and the flags hang from it in a row: one pennant is what is seen.
|
|
62
|
+
if (full)
|
|
63
|
+
out += el("path", { class: "ky-pl-fp", d: `M${num(px - 1.3)} ${num(surfaceY - h)}h2.6l${num(-1.3)} 3.1Z` });
|
|
64
|
+
out += textOn(turned, px, surfaceY - h - 1.4, `${SWIMMING.flags.at} m`, { size: 2, anchor: "middle", cls: "ky-pl-sx" });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// The false start rope: 1.2 m or more above the water, 15 m from the starting end.
|
|
68
|
+
if (plan.falseStart) {
|
|
69
|
+
const px = feet(SWIMMING.falseStart.at);
|
|
70
|
+
const h = v(SWIMMING.falseStart.height);
|
|
71
|
+
out += el("path", { class: "ky-line ky-pl-pole", d: `M${num(px)} ${num(surfaceY)}V${num(surfaceY - h)}`, "stroke-width": 0.4, fill: "none" });
|
|
72
|
+
out += el("circle", { class: "ky-pl-fs", cx: px, cy: surfaceY - h, r: 0.8 });
|
|
73
|
+
out += textOn(turned, px, surfaceY - h - 1.4, `${SWIMMING.falseStart.at} m`, { size: 2, anchor: "middle", cls: "ky-pl-sx" });
|
|
74
|
+
}
|
|
75
|
+
// A lane rope at the surface: its floats half under the water.
|
|
76
|
+
out += el("path", { class: ft(o, ["lane-ropes", "rope-blue"], "ky-pl-r ky-pl-r-blue"), d: `M0 ${num(surfaceY)}H${num(L)}`, "stroke-width": 1.7, "stroke-dasharray": "0 1.45", fill: "none" });
|
|
77
|
+
// The lane marking on the floor, and the depth.
|
|
78
|
+
out += el("path", { class: "ky-line", d: `M${num(feet(SWIMMING.laneLine.endGap))} ${num(floorY - 0.3)}H${num(L - feet(SWIMMING.laneLine.endGap))}`, "stroke-width": 0.5, fill: "none" });
|
|
79
|
+
const dx = -wall - 2.2;
|
|
80
|
+
out += el("path", { class: "ky-line ky-pl-dm", d: `M${num(dx)} ${num(surfaceY)}V${num(floorY)}M${num(dx - 0.9)} ${num(surfaceY)}H${num(dx + 0.9)}M${num(dx - 0.9)} ${num(floorY)}H${num(dx + 0.9)}`, "stroke-width": 0.3, fill: "none" });
|
|
81
|
+
out += textOn(turned, dx - 1.4, (surfaceY + floorY) / 2 + 0.7, `${num(depth)} m`, { size: 2.2, anchor: "end", cls: "ky-pl-sx" });
|
|
82
|
+
return { markup: el("g", { class: "ky-pl-section" }, out), height: floorY + wall - top, defs };
|
|
83
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DeckLook, PoolLook, PoolSport } from "./pool.types.ts";
|
|
2
|
+
/** What a drawing of a pool has in it, so that its stylesheet carries only what it needs. */
|
|
3
|
+
export interface PoolStyleUse {
|
|
4
|
+
sport: PoolSport;
|
|
5
|
+
look: PoolLook;
|
|
6
|
+
deck: DeckLook;
|
|
7
|
+
/** The lanes of a race are drawn: the plates, the medals, the pace bars. */
|
|
8
|
+
race: boolean;
|
|
9
|
+
/** A side section is drawn. */
|
|
10
|
+
section: boolean;
|
|
11
|
+
/** Several pools in one hall: the names of the pools. */
|
|
12
|
+
hall?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The stylesheet of a pool drawing, with only what it uses: the palette for its sport, the rules of the ropes, its sport's own, and, if it has them, the light on the water, the tiles, the labels of a race and a
|
|
16
|
+
* section.
|
|
17
|
+
*/
|
|
18
|
+
export declare function poolStyle(use: PoolStyleUse): string;
|
|
19
|
+
/** The rules of every pool, for a page that draws with `style: "none"` and supplies the stylesheet itself. */
|
|
20
|
+
export declare const KYOGIJO_POOL_STYLE: string;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// The stylesheet of the pools: the colours of the water, the deck, the lane ropes and the fixtures, in light and in dark, at no weight (`:where()`) so that a look, a page's rule and the options' `colors` all win,
|
|
2
|
+
// and the rule of each class a pool is drawn with. The rules of the sports do not set a colour for a deck or the water (they do for the lane ropes: green, blue, yellow, and red floats near the walls, which are
|
|
3
|
+
// kept in every look). These are our colours. A drawing carries only the rules its pool uses: the sport's, the light on the water if it has it, the labels of a race if there is one; a page that draws with
|
|
4
|
+
// `style: "none"` takes `KYOGIJO_POOL_STYLE`, which has them all.
|
|
5
|
+
import { POOL_SPORTS } from "./pool.js";
|
|
6
|
+
/** The colours that change between light and dark, by custom property; the rest do not change. */
|
|
7
|
+
const LIGHT = {
|
|
8
|
+
"--ky-surface": "#3fb4e6",
|
|
9
|
+
"--ky-surface-alt": "#2a9bd2",
|
|
10
|
+
"--ky-apron": "#e3e1d9",
|
|
11
|
+
"--ky-boards": "#f7f6f1",
|
|
12
|
+
"--ky-line": "#0c3a5c",
|
|
13
|
+
"--ky-plate": "rgba(14,24,32,.88)",
|
|
14
|
+
"--ky-pd": "#f3d32c",
|
|
15
|
+
"--ky-pk": "#454f59",
|
|
16
|
+
"--ky-pe": "#16212a",
|
|
17
|
+
"--ky-ps": "#39424a",
|
|
18
|
+
"--ky-pc": "#cdd2d7",
|
|
19
|
+
"--ky-pw": "#fbfcfd",
|
|
20
|
+
};
|
|
21
|
+
const DARK = {
|
|
22
|
+
"--ky-surface": "#1d7aa8",
|
|
23
|
+
"--ky-surface-alt": "#176b97",
|
|
24
|
+
"--ky-apron": "#1f252a",
|
|
25
|
+
"--ky-boards": "#3a434b",
|
|
26
|
+
"--ky-line": "#031118",
|
|
27
|
+
"--ky-plate": "rgba(0,0,0,.84)",
|
|
28
|
+
"--ky-pd": "#dcc23a",
|
|
29
|
+
"--ky-pk": "#6a7683",
|
|
30
|
+
"--ky-pe": "#05090c",
|
|
31
|
+
"--ky-ps": "#8793a0",
|
|
32
|
+
"--ky-pc": "#66727d",
|
|
33
|
+
"--ky-pw": "#e9eef2",
|
|
34
|
+
};
|
|
35
|
+
/** The colours that are the same in both modes: the lane ropes and the fixtures' accents (the rules fix the ropes' colours, and a look may change them). */
|
|
36
|
+
const SAME = {
|
|
37
|
+
"--ky-pg": "#1fa35a",
|
|
38
|
+
"--ky-pb": "#1b66d3",
|
|
39
|
+
"--ky-py": "#f4c514",
|
|
40
|
+
"--ky-pr": "#e0392f",
|
|
41
|
+
"--ky-pf": "#ff7a1a",
|
|
42
|
+
"--ky-fa": "#e0392f",
|
|
43
|
+
"--ky-fb": "#fff",
|
|
44
|
+
"--ky-pbd": "#e8691d",
|
|
45
|
+
"--ky-layer-home": "#ffd23f",
|
|
46
|
+
"--ky-layer-away": "#ff7a59",
|
|
47
|
+
"--ky-layer-ink": "#071a2b",
|
|
48
|
+
};
|
|
49
|
+
/** The light on the water and the tiles, which a pool has only in the looks that draw them. */
|
|
50
|
+
const LIGHT_PAINT = { "--ky-pla": "rgba(255,255,255,.34)", "--ky-ptl": "rgba(255,255,255,.2)", "--ky-pda": "rgba(120,112,98,.06)", "--ky-pdj": "rgba(90,84,72,.16)" };
|
|
51
|
+
const DARK_PAINT = { "--ky-pla": "rgba(190,235,255,.3)", "--ky-ptl": "rgba(190,235,255,.14)", "--ky-pda": "rgba(255,255,255,.04)", "--ky-pdj": "rgba(255,255,255,.1)" };
|
|
52
|
+
const declarations = (table) => Object.entries(table)
|
|
53
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
54
|
+
.join(";");
|
|
55
|
+
const RULES = {
|
|
56
|
+
common: [
|
|
57
|
+
".kyogijo .ky-pl-r{fill:none;stroke-linecap:round}",
|
|
58
|
+
".kyogijo .ky-pl-r-green{stroke:var(--ky-pg)}",
|
|
59
|
+
".kyogijo .ky-pl-r-blue{stroke:var(--ky-pb)}",
|
|
60
|
+
".kyogijo .ky-pl-r-yellow{stroke:var(--ky-py)}",
|
|
61
|
+
".kyogijo .ky-pl-r-red{stroke:var(--ky-pr)}",
|
|
62
|
+
".kyogijo .ky-pl-r-white{stroke:var(--ky-pw)}",
|
|
63
|
+
],
|
|
64
|
+
light: [".kyogijo .ky-pl-sa{stop-color:var(--ky-surface)}", ".kyogijo .ky-pl-sb,.kyogijo .ky-pl-sc{stop-color:var(--ky-surface-alt)}", ".kyogijo .ky-pl-lt{fill:var(--ky-pla);fill-opacity:.08;stroke:var(--ky-pla);stroke-width:.2;stroke-linejoin:round}"],
|
|
65
|
+
floor: [".kyogijo .ky-pl-ft{fill:none;stroke:var(--ky-ptl);stroke-width:.14}"],
|
|
66
|
+
deck: [".kyogijo .ky-pl-da{fill:var(--ky-pda)}", ".kyogijo .ky-pl-dt{fill:none;stroke:var(--ky-pdj);stroke-width:.12}"],
|
|
67
|
+
swimming: [
|
|
68
|
+
".kyogijo .ky-pl-pad{fill:var(--ky-pd);stroke:var(--ky-pe);stroke-width:.14;stroke-linejoin:round}",
|
|
69
|
+
".kyogijo .ky-pl-bk{fill:var(--ky-pk);stroke:var(--ky-pe);stroke-width:.12;stroke-linejoin:round}",
|
|
70
|
+
".kyogijo .ky-pl-bn{fill:#fff}",
|
|
71
|
+
".kyogijo .ky-pl-fa{stroke:var(--ky-fa);fill:none}",
|
|
72
|
+
".kyogijo .ky-pl-fb2{stroke:var(--ky-fb);fill:none}",
|
|
73
|
+
".kyogijo .ky-pl-fs{stroke:var(--ky-pf);fill:none}",
|
|
74
|
+
".kyogijo .ky-pl-st{fill:var(--ky-ps);stroke:var(--ky-pe);stroke-width:.1}",
|
|
75
|
+
],
|
|
76
|
+
race: [
|
|
77
|
+
".kyogijo .ky-pl-pl{fill:var(--ky-plate)}",
|
|
78
|
+
".kyogijo .ky-pl-nm,.kyogijo .ky-pl-tm{fill:var(--ky-plate-ink);font-weight:800}",
|
|
79
|
+
".kyogijo .ky-pl-ab,.kyogijo .ky-pl-sp,.kyogijo .ky-pl-rc{fill:var(--ky-plate-ink);opacity:.78;font-weight:700}",
|
|
80
|
+
".kyogijo .ky-pl-ld{fill:var(--ky-plate-ink)}",
|
|
81
|
+
".kyogijo .ky-pl-dn{fill:#10161c;text-anchor:middle}",
|
|
82
|
+
".kyogijo .ky-pl-mm{stroke:rgba(0,0,0,.35);stroke-width:.2}",
|
|
83
|
+
".kyogijo .ky-pl-mr{fill:none;stroke:rgba(255,255,255,.55);stroke-width:.25}",
|
|
84
|
+
".kyogijo .ky-pl-fb{stroke:rgba(255,255,255,.55);stroke-width:.18}",
|
|
85
|
+
".kyogijo .ky-pl-pb{stroke:rgba(0,0,0,.35);stroke-width:.18}",
|
|
86
|
+
".kyogijo .ky-pl-pt-d{fill:#10161c}",
|
|
87
|
+
".kyogijo .ky-pl-pt-l{fill:#fff}",
|
|
88
|
+
".kyogijo .ky-pl-ev{font-weight:800}",
|
|
89
|
+
".kyogijo .ky-pl-ax{opacity:.85;font-weight:700}",
|
|
90
|
+
".kyogijo .ky-pl-tick{opacity:.7}",
|
|
91
|
+
],
|
|
92
|
+
section: [
|
|
93
|
+
".kyogijo .ky-pl-sw{fill:var(--ky-boards);stroke:var(--ky-pe);stroke-width:.2;stroke-linejoin:round}",
|
|
94
|
+
".kyogijo .ky-pl-lm,.kyogijo .ky-pl-dm{stroke:var(--ky-ink)}",
|
|
95
|
+
".kyogijo .ky-pl-sx{font-weight:700}",
|
|
96
|
+
".kyogijo .ky-pl-pole{stroke:var(--ky-ps)}",
|
|
97
|
+
".kyogijo .ky-pl-fp{fill:var(--ky-fa);stroke:var(--ky-pe);stroke-width:.12;stroke-linejoin:round}",
|
|
98
|
+
],
|
|
99
|
+
waterpolo: [
|
|
100
|
+
".kyogijo .ky-pl-rp{stroke:var(--ky-pe);stroke-width:.1}",
|
|
101
|
+
".kyogijo .ky-pl-rp-red{fill:var(--ky-pr)}",
|
|
102
|
+
".kyogijo .ky-pl-rp-yellow{fill:var(--ky-py)}",
|
|
103
|
+
".kyogijo .ky-pl-rp-green{fill:var(--ky-pg)}",
|
|
104
|
+
".kyogijo .ky-pl-wl{fill:none}",
|
|
105
|
+
".kyogijo .ky-pl-wl-white{stroke:var(--ky-pw)}",
|
|
106
|
+
".kyogijo .ky-pl-wl-red{stroke:var(--ky-pr)}",
|
|
107
|
+
".kyogijo .ky-pl-wl-yellow{stroke:var(--ky-py)}",
|
|
108
|
+
".kyogijo .ky-pl-ra{fill:var(--ky-pr);fill-opacity:.4;stroke:var(--ky-pr);stroke-width:.2}",
|
|
109
|
+
".kyogijo .ky-pl-gn{stroke:var(--ky-pw);opacity:.85}",
|
|
110
|
+
".kyogijo .ky-pl-gb{stroke:var(--ky-pw)}",
|
|
111
|
+
".kyogijo .ky-pl-gp{fill:var(--ky-pw);stroke:var(--ky-pe);stroke-width:.12}",
|
|
112
|
+
".kyogijo .ky-pl-tb{fill:var(--ky-pk);stroke:var(--ky-pe);stroke-width:.14}",
|
|
113
|
+
".kyogijo .ky-pl-sa-l{fill:var(--ky-left)}",
|
|
114
|
+
".kyogijo .ky-pl-sa-r{fill:var(--ky-right)}",
|
|
115
|
+
],
|
|
116
|
+
diving: [
|
|
117
|
+
".kyogijo .ky-pl-sd{fill:var(--ky-boards);stroke:var(--ky-pe);stroke-width:.14}",
|
|
118
|
+
".kyogijo .ky-pl-pf{fill:var(--ky-pc);stroke:var(--ky-pe);stroke-width:.14}",
|
|
119
|
+
".kyogijo .ky-pl-spb{fill:var(--ky-pbd);stroke:var(--ky-pe);stroke-width:.12}",
|
|
120
|
+
".kyogijo .ky-pl-fe{stroke:var(--ky-pe)}",
|
|
121
|
+
".kyogijo .ky-pl-pm{fill:var(--ky-pr);stroke:var(--ky-pe);stroke-width:.08}",
|
|
122
|
+
".kyogijo .ky-pl-bt{fill:var(--ky-pe);text-anchor:middle}",
|
|
123
|
+
".kyogijo .ky-pl-bu{fill:var(--ky-ink)}",
|
|
124
|
+
],
|
|
125
|
+
artisticswimming: [
|
|
126
|
+
".kyogijo .ky-pl-dp{fill:#06223c;fill-opacity:.22}",
|
|
127
|
+
".kyogijo .ky-pl-dpl{stroke:var(--ky-line)}",
|
|
128
|
+
".kyogijo .ky-pl-jp,.kyogijo .ky-pl-sp2{fill:var(--ky-pk);stroke:var(--ky-pe);stroke-width:.14}",
|
|
129
|
+
".kyogijo .ky-pl-ch{fill:var(--ky-pw)}",
|
|
130
|
+
],
|
|
131
|
+
hall: [".kyogijo .ky-pl-vn{fill:var(--ky-ink)}", ".kyogijo .ky-pl-hw{fill:none;stroke:var(--ky-pe);stroke-width:.7;stroke-opacity:.55}", ".kyogijo .ky-pl-seat{fill:var(--ky-pk);fill-opacity:.2;stroke:var(--ky-pe);stroke-width:.3;stroke-opacity:.5}", ".kyogijo .ky-pl-rows{fill:none;stroke:var(--ky-pe);stroke-width:.25;stroke-opacity:.35}"],
|
|
132
|
+
};
|
|
133
|
+
/** The palette's rules for one or more sports (`.kyogijo[data-sport=...]`): in light, in dark by the device's setting, and in dark by the page's or the drawing's own. */
|
|
134
|
+
function palette(sports, paint) {
|
|
135
|
+
const light = { ...LIGHT, ...SAME, ...(paint ? LIGHT_PAINT : {}) };
|
|
136
|
+
const dark = { ...DARK, ...(paint ? DARK_PAINT : {}) };
|
|
137
|
+
return [
|
|
138
|
+
`:where(${sports.map((s) => `.kyogijo[data-sport=${s}]`).join(",")}){${declarations(light)}}`,
|
|
139
|
+
`@media (prefers-color-scheme:dark){:where(${sports.map((s) => `html:not([data-theme=light]) .kyogijo[data-sport=${s}]:not([data-theme=light])`).join(",")}){${declarations(dark)}}}`,
|
|
140
|
+
`:where(${sports.flatMap((s) => [`html[data-theme=dark] .kyogijo[data-sport=${s}]`, `.kyogijo[data-theme=dark][data-sport=${s}]`]).join(",")}){${declarations(dark)}}`,
|
|
141
|
+
].join("\n");
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The stylesheet of a pool drawing, with only what it uses: the palette for its sport, the rules of the ropes, its sport's own, and, if it has them, the light on the water, the tiles, the labels of a race and a
|
|
145
|
+
* section.
|
|
146
|
+
*/
|
|
147
|
+
export function poolStyle(use) {
|
|
148
|
+
const lit = use.look !== "flat";
|
|
149
|
+
const parts = [palette([use.sport], lit || use.deck === "tiled"), ...RULES.common];
|
|
150
|
+
if (lit)
|
|
151
|
+
parts.push(...RULES.light);
|
|
152
|
+
if (use.look === "tiled")
|
|
153
|
+
parts.push(...RULES.floor);
|
|
154
|
+
if (use.deck === "tiled")
|
|
155
|
+
parts.push(...RULES.deck);
|
|
156
|
+
if (use.sport === "swimming")
|
|
157
|
+
parts.push(...RULES.swimming);
|
|
158
|
+
if (use.race)
|
|
159
|
+
parts.push(...RULES.race);
|
|
160
|
+
if (use.section)
|
|
161
|
+
parts.push(...RULES.section);
|
|
162
|
+
if (use.hall === true)
|
|
163
|
+
parts.push(...RULES.hall);
|
|
164
|
+
if (use.sport === "waterpolo" || use.sport === "diving" || use.sport === "artisticswimming")
|
|
165
|
+
parts.push(...RULES[use.sport]);
|
|
166
|
+
return parts.join("\n");
|
|
167
|
+
}
|
|
168
|
+
/** The rules of every pool, for a page that draws with `style: "none"` and supplies the stylesheet itself. */
|
|
169
|
+
export const KYOGIJO_POOL_STYLE = [palette(POOL_SPORTS, true), ...RULES.common, ...RULES.light, ...RULES.floor, ...RULES.deck, ...RULES.swimming, ...RULES.race, ...RULES.section, ...RULES.waterpolo, ...RULES.diving, ...RULES.artisticswimming, ...RULES.hall].join("\n");
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/** The sports of the pool: the swimming pool, the water polo field, the diving well and the artistic swimming area. */
|
|
2
|
+
export type PoolSport = "swimming" | "waterpolo" | "diving" | "artisticswimming";
|
|
3
|
+
/**
|
|
4
|
+
* How the water is painted: `flat` (the default) is one clean colour; `water` lays a faint, seeded pattern of light on it, deeper blue at the middle of a long pool; `tiled` shows the tiles of the floor
|
|
5
|
+
* through the water as well.
|
|
6
|
+
*/
|
|
7
|
+
export type PoolLook = "flat" | "water" | "tiled";
|
|
8
|
+
/** How the deck is painted: one colour, or in tiles. */
|
|
9
|
+
export type DeckLook = "plain" | "tiled";
|
|
10
|
+
/** The swimming pool of a competition, or a warm-up pool: the same lanes and ropes, without the starting blocks, the flags and the false start rope. */
|
|
11
|
+
export type PoolKind = "competition" | "warm-up";
|
|
12
|
+
/** Why a swimmer has no time. */
|
|
13
|
+
export type SwimmerStatus = "dq" | "dns" | "dnf";
|
|
14
|
+
/**
|
|
15
|
+
* One swimmer in a lane: who is in it, and, once the race is swum, what happened. The caller passes the flag (an `https:` address, an image `data:` address or an SVG document as text, held to the rules of
|
|
16
|
+
* a team's `logo`); the package bundles no flags. Times are seconds (`26.12`) or text (`"1:46.91"`).
|
|
17
|
+
*/
|
|
18
|
+
export interface Swimmer {
|
|
19
|
+
/** The lane, as the pool numbers them (1 to 8, or 0 to 9 in a ten-lane pool). */
|
|
20
|
+
lane: number;
|
|
21
|
+
name: string;
|
|
22
|
+
/** A short form for the label: the country's three letters, or a club's. */
|
|
23
|
+
abbr?: string;
|
|
24
|
+
/** The flag or crest, drawn small beside the name. */
|
|
25
|
+
flag?: string;
|
|
26
|
+
/** The swimmer's colour (a cap, a club), drawn as a stripe on the label. */
|
|
27
|
+
color?: string;
|
|
28
|
+
/** The entry time. */
|
|
29
|
+
seed?: number | string;
|
|
30
|
+
/** The final time. */
|
|
31
|
+
time?: number | string;
|
|
32
|
+
/** The place: 1, 2 and 3 get a gold, a silver and a bronze medal. Worked out from the times when it is missing and every swimmer has one. */
|
|
33
|
+
place?: number;
|
|
34
|
+
/** The reaction time off the block, in seconds (`0.62`). */
|
|
35
|
+
reaction?: number;
|
|
36
|
+
/** The cumulative time at each split: at 50, 100 and 150 m of a 200 m race, or each 25 m of a short course. The last is the final time. */
|
|
37
|
+
splits?: readonly (number | string | null | undefined)[];
|
|
38
|
+
/** `dq`, `dns` or `dnf`, written in place of a time. */
|
|
39
|
+
status?: SwimmerStatus;
|
|
40
|
+
/** A record the swim set: `WR`, `OR`, `CR`... written beside the time. */
|
|
41
|
+
record?: string;
|
|
42
|
+
}
|
|
43
|
+
/** What the labels of a race show. Everything that has data is shown unless it says `false`. */
|
|
44
|
+
export interface RaceShow {
|
|
45
|
+
names?: boolean;
|
|
46
|
+
flags?: boolean;
|
|
47
|
+
results?: boolean;
|
|
48
|
+
reaction?: boolean;
|
|
49
|
+
splits?: boolean;
|
|
50
|
+
medals?: boolean;
|
|
51
|
+
seeds?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** The split pace bars drawn in the lanes: each split of a race as a bar whose length is the share of the lane that split is, and whose colour is its pace against the field's. */
|
|
54
|
+
export interface PaceOptions {
|
|
55
|
+
/** Write the pace in seconds per 100 m on each bar. On by default. */
|
|
56
|
+
labels?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** A race: the event, its distance, and the swimmers in their lanes. */
|
|
59
|
+
export interface PoolRace {
|
|
60
|
+
/** The name of the event: "Women's 200 m butterfly, final". */
|
|
61
|
+
event?: string;
|
|
62
|
+
/** The distance in metres. Worked out from the splits (the number of splits times the distance between them) when it is missing, else the length of the course. */
|
|
63
|
+
distance?: number;
|
|
64
|
+
/** The metres between two splits: 50 in a long course pool and 25 in a short course one, unless this says another. */
|
|
65
|
+
splitEvery?: number;
|
|
66
|
+
swimmers: readonly Swimmer[];
|
|
67
|
+
show?: RaceShow;
|
|
68
|
+
/** Draw the splits as pace bars in the lanes. */
|
|
69
|
+
pace?: boolean | PaceOptions;
|
|
70
|
+
}
|
|
71
|
+
/** The boards of a diving well that can be asked for. */
|
|
72
|
+
export type DivingPlatform = 1 | 3 | 5 | 7.5 | 10;
|
|
73
|
+
/** One pool of a natatorium: which pool it is, and where, in metres from the hall's top left corner. A pool with no place is put by the layout. */
|
|
74
|
+
export interface VenuePool {
|
|
75
|
+
sport: PoolSport;
|
|
76
|
+
/** A name for the plan's label. The pool's own by default. */
|
|
77
|
+
name?: string;
|
|
78
|
+
/** For a swimming pool: its course and kind (`short` and `warm-up` for a warm-up pool). */
|
|
79
|
+
course?: "long" | "short";
|
|
80
|
+
kind?: PoolKind;
|
|
81
|
+
lanes?: number;
|
|
82
|
+
x?: number;
|
|
83
|
+
y?: number;
|
|
84
|
+
}
|
|
85
|
+
/** A natatorium: several pools in one hall, to scale, kept the distance the rules ask of a swimming pool and a diving well. */
|
|
86
|
+
export interface VenueOptions {
|
|
87
|
+
pools: readonly VenuePool[];
|
|
88
|
+
/** The metres between two pools. 10 (the preferred distance of the rules) by default. */
|
|
89
|
+
apart?: number;
|
|
90
|
+
/** Write each pool's name on the plan. On by default. */
|
|
91
|
+
labels?: boolean;
|
|
92
|
+
/** Draw the seating for spectators along the top of the hall. On by default. */
|
|
93
|
+
seating?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** A side section of a swimming pool: its depth profile, the blocks, the flags and the false start rope. */
|
|
96
|
+
export interface PoolSection {
|
|
97
|
+
/** The water's depth in metres. The rules' least for the pool: 2.5 for a 50 m pool, 2.0 for a 25 m one. */
|
|
98
|
+
depth?: number;
|
|
99
|
+
/** How much taller than long the section is drawn. 2.5 by default; the section is not to scale otherwise. */
|
|
100
|
+
exaggerate?: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The look, the size and the data of a pool. Every part is optional. The sport (`swimming`, `waterpolo`, `diving`, `artisticswimming`) says which pool it is; the parts that belong to one pool are
|
|
104
|
+
* said so in their descriptions.
|
|
105
|
+
*/
|
|
106
|
+
export interface PoolStyle {
|
|
107
|
+
/** Swimming: `long` (50 m, the default) or `short` (25 m). */
|
|
108
|
+
course?: "long" | "short";
|
|
109
|
+
/** Swimming: the lanes, 1 to 10. 8 by default. Ten lanes are numbered 0 to 9. */
|
|
110
|
+
lanes?: number;
|
|
111
|
+
/** Swimming: a temporary pool (26 m wide, ten lanes of 2.5 m) in place of a permanent one (25 m, lanes 0 and 9 of 2.4 m). Only for a ten-lane pool. */
|
|
112
|
+
temporary?: boolean;
|
|
113
|
+
/** Swimming: `competition` (the default) or `warm-up`, a pool of the same lanes without blocks, flags or false start rope. */
|
|
114
|
+
kind?: PoolKind;
|
|
115
|
+
/** How the water is painted: `flat`, `water` or `tiled`. */
|
|
116
|
+
look?: PoolLook;
|
|
117
|
+
/** `plain` or `tiled` deck. */
|
|
118
|
+
deck?: DeckLook;
|
|
119
|
+
/** The seed of the light on the water (`look: "water"`). The same seed always draws the same light. 1 by default. */
|
|
120
|
+
seed?: number;
|
|
121
|
+
/** Swimming: the starting blocks, with their lane numbers. On in a competition pool. */
|
|
122
|
+
blocks?: boolean;
|
|
123
|
+
/** Swimming: the touch panels on the end walls. On in a competition pool. */
|
|
124
|
+
pads?: boolean;
|
|
125
|
+
/** Swimming: the backstroke turn flags at 5 m from each end. On in a competition pool. */
|
|
126
|
+
flags?: boolean;
|
|
127
|
+
/** Swimming: the false start rope at 15 m from the starting end. On in a competition pool. */
|
|
128
|
+
falseStart?: boolean;
|
|
129
|
+
/** Swimming: a side section under the plan, with the depth. */
|
|
130
|
+
section?: boolean | PoolSection;
|
|
131
|
+
/** Swimming: the lanes of a race, with the names, the flags, the results and the splits. */
|
|
132
|
+
race?: PoolRace;
|
|
133
|
+
/** Water polo: the side of the field the official table is on, as the field is drawn wide: `bottom` (the default) or `top`. */
|
|
134
|
+
table?: "top" | "bottom";
|
|
135
|
+
/** Diving: the platforms to draw (1, 3, 5, 7.5, 10). 5, 7.5 and 10 by default. */
|
|
136
|
+
platforms?: readonly DivingPlatform[];
|
|
137
|
+
/** Diving: draw the springboards (the 1 m and the 3 m). On by default. */
|
|
138
|
+
springboards?: boolean;
|
|
139
|
+
/** Diving: how many boards of each height, 2 each by default (a synchronised pair stands side by side). */
|
|
140
|
+
boards?: number;
|
|
141
|
+
/** Artistic swimming: the routine area of the Olympic Games and the World Championships (`olympic`, 30 by 20 m) or the least (`minimum`, 25 by 15 m with a 12 by 12 m deep part). */
|
|
142
|
+
area?: "olympic" | "minimum";
|
|
143
|
+
/** Several pools in one hall: `natatorium`, or a list of your own. Swimming only; the pool of the options is the competition pool. */
|
|
144
|
+
venue?: "natatorium" | VenueOptions;
|
|
145
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PoolPlan } from "./pool.ts";
|
|
2
|
+
import { STATUS_TEXT } from "./pool.race.ts";
|
|
3
|
+
import type { Language, SurfaceOptions } from "./types.ts";
|
|
4
|
+
/** The plan of a pool sport's options. */
|
|
5
|
+
export declare function planOf(o: Pick<SurfaceOptions, "sport" | "pool">): PoolPlan;
|
|
6
|
+
/** Items as a list in a language: "a, b and c". */
|
|
7
|
+
export declare function listOf(items: readonly string[], language: Language): string;
|
|
8
|
+
/** What the pool is, as a fragment for the description, and the sentences that follow it. */
|
|
9
|
+
export declare function poolDescription(o: Pick<SurfaceOptions, "sport" | "pool">, language: Language): {
|
|
10
|
+
about: string;
|
|
11
|
+
after: string[];
|
|
12
|
+
};
|
|
13
|
+
export { STATUS_TEXT };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// What a pool says of itself in a drawing's description, in a language: what the pool is, how big, with how many lanes or which boards, the lanes of a race with their places, times and splits, and the side section.
|
|
2
|
+
import { artisticPlan, divePlan, poloPlan, swimPlan, venueOf } from "./pool.js";
|
|
3
|
+
import { STATUS_TEXT, formatTime } from "./pool.race.js";
|
|
4
|
+
import { MEDALS } from "./pool.labels.js";
|
|
5
|
+
import { WATER_POLO } from "./pool.figures.js";
|
|
6
|
+
import { KYOGIJO_STRINGS, fill } from "./strings.js";
|
|
7
|
+
const trimmed = (value) => String(Math.round(value * 100) / 100);
|
|
8
|
+
/** The plan of a pool sport's options. */
|
|
9
|
+
export function planOf(o) {
|
|
10
|
+
switch (o.sport) {
|
|
11
|
+
case "swimming":
|
|
12
|
+
return swimPlan(o);
|
|
13
|
+
case "waterpolo":
|
|
14
|
+
return poloPlan(o);
|
|
15
|
+
case "diving":
|
|
16
|
+
return divePlan(o);
|
|
17
|
+
default:
|
|
18
|
+
return artisticPlan(o);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const sizeText = (language, length, width) => fill(KYOGIJO_STRINGS[language].pool.size, { length: trimmed(length), width: trimmed(width) });
|
|
22
|
+
/** Items as a list in a language: "a, b and c". */
|
|
23
|
+
export function listOf(items, language) {
|
|
24
|
+
const w = KYOGIJO_STRINGS[language].pool;
|
|
25
|
+
return items.length < 2 ? items.join("") : `${items.slice(0, -1).join(w.sep)}${w.last}${items[items.length - 1]}`;
|
|
26
|
+
}
|
|
27
|
+
/** The sentences about the lanes of a race, one for each swimmer that has a lane, in the order down the page. */
|
|
28
|
+
function raceSentences(plan, language) {
|
|
29
|
+
const race = plan.race;
|
|
30
|
+
if (race === undefined)
|
|
31
|
+
return [];
|
|
32
|
+
const words = KYOGIJO_STRINGS[language];
|
|
33
|
+
const w = words.pool;
|
|
34
|
+
const { stop } = words.said;
|
|
35
|
+
const out = [];
|
|
36
|
+
if (race.event !== undefined)
|
|
37
|
+
out.push(`${fill(w.event, { event: race.event })}${/[.。]$/.test(race.event) ? "" : stop}`);
|
|
38
|
+
for (const row of race.rows) {
|
|
39
|
+
const parts = [`${fill(w.lane, { lane: row.lane, name: row.name })}${row.abbr === "" ? "" : fill(w.abbr, { abbr: row.abbr })}`];
|
|
40
|
+
if (race.show.results && row.status !== undefined)
|
|
41
|
+
parts.push(w.status[row.status]);
|
|
42
|
+
else if (race.show.results) {
|
|
43
|
+
if (row.place !== undefined)
|
|
44
|
+
parts.push(fill(w.place, { n: row.place }));
|
|
45
|
+
if (race.show.medals && row.place !== undefined && MEDALS[row.place] !== undefined)
|
|
46
|
+
parts.push(w.medal[["gold", "silver", "bronze"][row.place - 1]]);
|
|
47
|
+
if (row.timeText !== undefined)
|
|
48
|
+
parts.push(fill(w.time, { time: row.timeText }));
|
|
49
|
+
if (race.show.reaction && row.reaction !== undefined)
|
|
50
|
+
parts.push(fill(w.reaction, { rt: row.reaction.toFixed(2) }));
|
|
51
|
+
if (race.show.splits && row.splits.some((s) => Number.isFinite(s)))
|
|
52
|
+
parts.push(fill(w.splits, { list: row.splits.filter((s) => Number.isFinite(s)).map(formatTime).join(w.joiner) }));
|
|
53
|
+
if (row.record !== undefined)
|
|
54
|
+
parts.push(fill(w.record, { record: row.record }));
|
|
55
|
+
}
|
|
56
|
+
if (race.show.seeds && row.seed !== undefined && row.timeText === undefined && row.status === undefined)
|
|
57
|
+
parts.push(fill(w.seed, { time: row.seed }));
|
|
58
|
+
out.push(`${parts.join(w.joiner)}${stop}`);
|
|
59
|
+
}
|
|
60
|
+
if (race.pace !== null && race.fastest !== undefined)
|
|
61
|
+
out.push(w.pace);
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/** What the pool is, as a fragment for the description, and the sentences that follow it. */
|
|
65
|
+
export function poolDescription(o, language) {
|
|
66
|
+
const words = KYOGIJO_STRINGS[language];
|
|
67
|
+
const w = words.pool;
|
|
68
|
+
const venue = o.sport === "swimming" && o.pool?.venue !== undefined ? venueOf(o.pool) : undefined;
|
|
69
|
+
if (venue !== undefined) {
|
|
70
|
+
const names = venue.pools.map((pool) => {
|
|
71
|
+
const key = pool.sport === "swimming" ? (pool.kind === "warm-up" ? "warmUp" : "competition") : pool.sport === "diving" ? "diving" : pool.sport === "waterpolo" ? "waterPolo" : "artistic";
|
|
72
|
+
return pool.name ?? w.names[key];
|
|
73
|
+
});
|
|
74
|
+
return { about: fill(w.venue, { n: venue.pools.length, list: listOf(names, language) }).replace(/[.。]$/, ""), after: [] };
|
|
75
|
+
}
|
|
76
|
+
const plan = planOf(o);
|
|
77
|
+
switch (plan.sport) {
|
|
78
|
+
case "swimming": {
|
|
79
|
+
const lanes = plan.lanes.length === 1 ? w.laneOne : fill(w.lanes, { n: plan.lanes.length });
|
|
80
|
+
const about = fill(plan.kind === "warm-up" ? w.aboutWarmUp : w.aboutSwimming, { size: sizeText(language, plan.length, plan.width), lanes });
|
|
81
|
+
const after = raceSentences(plan, language);
|
|
82
|
+
if (plan.section !== undefined)
|
|
83
|
+
after.push(fill(w.section, { depth: trimmed(plan.depth) }));
|
|
84
|
+
return { about, after };
|
|
85
|
+
}
|
|
86
|
+
case "waterpolo":
|
|
87
|
+
return { about: fill(w.aboutWaterPolo, { size: sizeText(language, WATER_POLO.length, WATER_POLO.width) }), after: [] };
|
|
88
|
+
case "diving": {
|
|
89
|
+
const heights = plan.boards.filter((b) => b.kind === "platform").map((b) => b.height).sort((a, b) => a - b);
|
|
90
|
+
const hasBoards = plan.boards.some((b) => b.kind === "springboard");
|
|
91
|
+
const list = listOf(heights.map(String), language);
|
|
92
|
+
const boards = [hasBoards ? w.boards : "", heights.length > 0 ? fill(w.platforms, { list }) : ""].filter((part) => part !== "").join(w.and);
|
|
93
|
+
return { about: fill(w.aboutDiving, { size: sizeText(language, plan.length, plan.width), boards: boards === "" ? "" : boards }).replace(/,\s*with\s*$/, "").replace(/で、があります$/, "です"), after: [] };
|
|
94
|
+
}
|
|
95
|
+
default: {
|
|
96
|
+
const deep = plan.deep === undefined ? "" : fill(w.deep, { size: sizeText(language, plan.deep.length, plan.deep.width) });
|
|
97
|
+
return { about: `${fill(w.aboutArtistic, { size: sizeText(language, plan.length, plan.width) })}${deep}`, after: [] };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export { STATUS_TEXT };
|
package/dist/ranges.names.js
CHANGED
|
@@ -17,12 +17,19 @@ export const RANGES = Object.freeze({
|
|
|
17
17
|
nba: Object.freeze([range("half-court", "left"), range("paint", "left")]),
|
|
18
18
|
soccer: Object.freeze([range("half", "left"), range("final-third", "right"), range("defensive-third", "left"), range("middle-third"), range("penalty-area", "left")]),
|
|
19
19
|
mlb: Object.freeze([range("infield"), range("outfield")]),
|
|
20
|
-
curling: Object.freeze([range("sheet"), range("half", "left"), range("house", "left")]),
|
|
20
|
+
curling: Object.freeze([range("sheet"), range("half", "left"), range("house", "left"), range("folded")]),
|
|
21
21
|
tennis: NET,
|
|
22
22
|
volleyball: NET,
|
|
23
23
|
badminton: NET,
|
|
24
24
|
pickleball: NET,
|
|
25
25
|
tabletennis: NET,
|
|
26
|
+
padel: NET,
|
|
27
|
+
squash: NET,
|
|
28
|
+
racquetball: NET,
|
|
29
|
+
sepaktakraw: NET,
|
|
30
|
+
teqball: NET,
|
|
31
|
+
roundnet: NET,
|
|
32
|
+
netball: NET,
|
|
26
33
|
lacrosse: Object.freeze([range("half", "left"), range("crease", "right")]),
|
|
27
34
|
rugby: Object.freeze([range("half", "left"), range("twenty-two", "right", ["world-rugby"]), range("twenty", "right", ["nrl", "irl"]), range("in-goal", "right")]),
|
|
28
35
|
afl: Object.freeze([range("half", "left"), range("forward-fifty", "right"), range("centre-square")]),
|
|
@@ -30,6 +37,41 @@ export const RANGES = Object.freeze({
|
|
|
30
37
|
cricket: Object.freeze([range("pitch"), range("circle", undefined, ["icc-men", "icc-women"])]),
|
|
31
38
|
fieldhockey: Object.freeze([range("half", "left"), range("circle", "right"), range("twenty-three", "right")]),
|
|
32
39
|
handball: Object.freeze([range("half", "left"), range("goal-area", "right")]),
|
|
40
|
+
swimming: Object.freeze([range("half", "left"), range("pool-end", "left")]),
|
|
41
|
+
waterpolo: Object.freeze([range("half", "left"), range("goal-area", "right")]),
|
|
42
|
+
diving: Object.freeze([range("springboards", "left"), range("platforms", "right")]),
|
|
43
|
+
artisticswimming: Object.freeze([range("half", "left"), range("centre-stage")]),
|
|
44
|
+
// The bends are the first (right) and the second (left); the field events are at the end of the stadium where the standard layout puts them (a range with two ends has both, one with one has that end).
|
|
45
|
+
// The long track, the short track and the figure skating rink share a sport: a range is for the leagues that have it.
|
|
46
|
+
skating: Object.freeze([
|
|
47
|
+
range("home-straight", undefined, ["isu-long-track", "isu-short-track"]),
|
|
48
|
+
range("crossing-straight", undefined, ["isu-long-track", "isu-short-track"]),
|
|
49
|
+
range("first-bend", "right", ["isu-long-track", "isu-short-track"]),
|
|
50
|
+
range("second-bend", "left", ["isu-long-track", "isu-short-track"]),
|
|
51
|
+
range("finish", undefined, ["isu-long-track", "isu-short-track"]),
|
|
52
|
+
range("start", undefined, ["isu-long-track", "isu-short-track"]),
|
|
53
|
+
range("infield", undefined, ["isu-long-track", "isu-short-track"]),
|
|
54
|
+
range("half", "left", ["isu-figure"]),
|
|
55
|
+
range("judges", undefined, ["isu-figure"]),
|
|
56
|
+
range("kiss-and-cry", "left", ["isu-figure"]),
|
|
57
|
+
]),
|
|
58
|
+
athletics: Object.freeze([
|
|
59
|
+
range("bend", "right"),
|
|
60
|
+
range("home-straight"),
|
|
61
|
+
range("back-straight"),
|
|
62
|
+
range("finish"),
|
|
63
|
+
range("start"),
|
|
64
|
+
range("infield"),
|
|
65
|
+
range("high-jump", "right"),
|
|
66
|
+
range("pole-vault", "left"),
|
|
67
|
+
range("long-jump"),
|
|
68
|
+
range("triple-jump"),
|
|
69
|
+
range("shot-put", "left"),
|
|
70
|
+
range("discus-throw", "right"),
|
|
71
|
+
range("hammer-throw", "right"),
|
|
72
|
+
range("javelin-throw", "left"),
|
|
73
|
+
range("water-jump", "left"),
|
|
74
|
+
]),
|
|
33
75
|
});
|
|
34
76
|
const isNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
35
77
|
/**
|
|
@@ -52,9 +94,11 @@ export function parseRange(o) {
|
|
|
52
94
|
const leagueId = league?.id ?? LEAGUES[sport]?.[0]?.id;
|
|
53
95
|
if (info.leagues !== undefined && leagueId !== undefined && !info.leagues.includes(leagueId))
|
|
54
96
|
throw new RangeError(`The ${sport} league "${leagueId}" has no range "${name}": it is for ${info.leagues.join(" and ")}`);
|
|
55
|
-
|
|
97
|
+
// A curling sheet's ends are also read as a tall sheet's: the top end is the left one and the bottom end the right.
|
|
98
|
+
const asked = sport === "curling" && end === "top" ? "left" : sport === "curling" && end === "bottom" ? "right" : end;
|
|
99
|
+
if (asked !== undefined && asked !== "left" && asked !== "right")
|
|
56
100
|
throw new RangeError(`A range's end is "left" or "right", not "${String(end)}"`);
|
|
57
|
-
return { kind: "name", name: info.id, end: info.end === undefined ? undefined : (
|
|
101
|
+
return { kind: "name", name: info.id, end: info.end === undefined ? undefined : (asked ?? info.end), asked: asked };
|
|
58
102
|
}
|
|
59
103
|
const box = given;
|
|
60
104
|
if (typeof given !== "object" || !isNumber(box.x0) || !isNumber(box.x1) || !isNumber(box.y0) || !isNumber(box.y1))
|
package/dist/replay-entry.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { activeEvents, describeEvent, drawFrame, eventsBetween, interpolate, possession, replayClock, replayEvents, replayInfo, replayLayers, replaySnapshot, replaySummary, replayTable, replayTimes, trails } from "./replay.ts";
|
|
2
2
|
export type { ReplaySnapshot } from "./replay.ts";
|
|
3
|
+
export { alongPool, distanceAt, progressOf, raceTimeline } from "./pool.replay.ts";
|
|
4
|
+
export type { Progress, RaceReplayOptions } from "./pool.replay.ts";
|
|
5
|
+
export { formatTime, parseTime } from "./pool.race.ts";
|
|
3
6
|
export { REPLAY_SPEEDS, REPLAY_SPEED_RANGE, createReplay } from "./replay.control.ts";
|
|
4
7
|
export type { ReplayController } from "./replay.control.ts";
|
|
5
8
|
export type { ActiveEvent, Possession, ReplayChange, ReplayEvent, ReplayEventKind, ReplayFrame, ReplayLook, ReplayObject, ReplayReason, ReplaySettings, ReplayState, ReplayTeam, ReplayTimeline, ReplayTrail, } from "./replay.types.ts";
|
package/dist/replay-entry.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// Replay: tracking data over time on a surface. The frame, the clock and the pure functions between them; the controls and the animation
|
|
2
2
|
// are in the mount (`mountKyogijo(...).replay(...)`) and in `<kyogijo-field>`.
|
|
3
3
|
export { activeEvents, describeEvent, drawFrame, eventsBetween, interpolate, possession, replayClock, replayEvents, replayInfo, replayLayers, replaySnapshot, replaySummary, replayTable, replayTimes, trails } from "./replay.js";
|
|
4
|
+
export { alongPool, distanceAt, progressOf, raceTimeline } from "./pool.replay.js";
|
|
5
|
+
export { formatTime, parseTime } from "./pool.race.js";
|
|
4
6
|
export { REPLAY_SPEEDS, REPLAY_SPEED_RANGE, createReplay } from "./replay.control.js";
|