@johnmorrisdotca/kyogijo-stadiums 0.7.0 → 0.9.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 +28 -0
- package/NOTICE.md +1 -0
- package/README.md +22 -20
- package/dist/budo/looks.js +1 -1
- package/dist/budo/room.d.ts +34 -2
- package/dist/budo/room.js +39 -7
- package/dist/budo/types.d.ts +6 -1
- package/dist/budo.style.d.ts +1 -1
- package/dist/budo.style.js +6 -3
- package/dist/charts.athletics.js +4 -3
- package/dist/charts.d.ts +8 -0
- package/dist/charts.js +13 -0
- package/dist/charts.skating.js +9 -7
- package/dist/crowd.d.ts +4 -0
- package/dist/crowd.draw.d.ts +5 -0
- package/dist/crowd.draw.js +34 -5
- package/dist/crowd.js +6 -1
- package/dist/draw.js +28 -15
- package/dist/element-entry.d.ts +2 -0
- package/dist/element-entry.js +1 -0
- package/dist/element.d.ts +3 -3
- package/dist/element.js +20 -3
- package/dist/flags-source.d.ts +37 -0
- package/dist/flags-source.js +60 -0
- package/dist/halls.js +4 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/layers.env.js +5 -2
- package/dist/layers.js +2 -1
- package/dist/logo.d.ts +6 -0
- package/dist/logo.js +8 -0
- package/dist/pool.labels.js +5 -3
- package/dist/pool.race.d.ts +2 -0
- package/dist/pool.race.js +1 -0
- package/dist/pool.types.d.ts +2 -0
- package/dist/strings.d.ts +7 -1
- package/dist/strings.js +6 -4
- package/dist/surfaces/budo.js +22 -2
- package/dist/team.lineup.js +2 -2
- package/dist/team.types.d.ts +2 -0
- package/dist/turn-entry.d.ts +2 -0
- package/dist/turn-entry.js +1 -0
- package/dist/turn.dom.d.ts +8 -0
- package/dist/turn.dom.js +147 -8
- package/dist/turn.kit.d.ts +5 -3
- package/dist/turn.kit.js +1 -1
- package/dist/turn.markup.d.ts +8 -1
- package/dist/turn.markup.js +18 -4
- package/dist/turn.model.d.ts +26 -0
- package/dist/turn.model.js +34 -3
- package/dist/turn.style.js +58 -4
- package/dist/types.d.ts +11 -0
- package/dist/uprights.d.ts +7 -0
- package/dist/uprights.js +15 -1
- package/dist/venue.d.ts +31 -0
- package/dist/venue.geom.d.ts +53 -0
- package/dist/venue.geom.js +225 -0
- package/dist/venue.js +172 -0
- package/dist/venue.room.d.ts +9 -0
- package/dist/venue.room.js +240 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -1
package/dist/crowd.draw.js
CHANGED
|
@@ -49,8 +49,10 @@ function tile(seed, density, share, team, neutral = false) {
|
|
|
49
49
|
return el("g", { fill: "none", "stroke-linecap": "round", "stroke-width": 2.3 }, out + headPaths);
|
|
50
50
|
}
|
|
51
51
|
/** The tiles a crowd needs: the home tile, the home tile of the upper tiers (emptier) and the visitors', and the display tiles. */
|
|
52
|
-
function patterns(id, crowd, density, tifo, neutral = false) {
|
|
53
|
-
|
|
52
|
+
export function patterns(id, crowd, density, tifo, neutral = false, rows = false) {
|
|
53
|
+
// A 3D view's tiles carry the lines of the rows too (a row every third of a tile, along the tile's x), so that a raked plane is textured and not drawn seat by seat.
|
|
54
|
+
const rowLines = rows ? el("path", { class: "ky-cr-row", d: `M0 .3H${TILE}M0 ${TILE / 3 + 0.3}H${TILE}M0 ${(2 * TILE) / 3 + 0.3}H${TILE}`, fill: "none" }) : "";
|
|
55
|
+
const make = (suffix, body, size = TILE) => el("pattern", { id: `${id}-cr-${suffix}`, width: size, height: size, patternUnits: "userSpaceOnUse" }, size === TILE ? body + rowLines : body);
|
|
54
56
|
let out = make("h", tile(crowd.seed * 7 + 1, density, neutral ? 0 : 0.88, "ky-cr-h", neutral)) + make("a", tile(crowd.seed * 7 + 3, Math.min(1, density * 1.04), 0.94, "ky-cr-a"));
|
|
55
57
|
if (tifo !== undefined) {
|
|
56
58
|
const stripes = (cls) => el("rect", { class: cls, width: 3, height: 6 }) + el("rect", { class: "ky-cr-tw", x: 3, width: 3, height: 6 });
|
|
@@ -105,6 +107,30 @@ function rows(ring) {
|
|
|
105
107
|
}
|
|
106
108
|
return d.length === 0 ? "" : el("path", { class: "ky-cr-row", d: d.join("") });
|
|
107
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The seats of a hall's gallery seen from above: its band stepped into rows (a gallery's rows are about 0.8 m, 2.6 feet, deep), each row a dashed line for the cushions with a thinner, darker one behind
|
|
112
|
+
* it for the backs, and the aisles across the band as lighter stripes between the blocks of seats. Plain seats and empty: the people, when asked for, are laid over.
|
|
113
|
+
*/
|
|
114
|
+
function galleryRows(ring) {
|
|
115
|
+
const h = ring.hole;
|
|
116
|
+
const depth = ring.to - ring.from;
|
|
117
|
+
const rows = ring.rows ?? Math.max(1, Math.round(depth / 2.62));
|
|
118
|
+
if (h === null || h.kind !== "rrect")
|
|
119
|
+
return "";
|
|
120
|
+
const step = depth / rows;
|
|
121
|
+
const line = (k) => outlinePath({ kind: "rrect", x0: h.x0 - k, y0: h.y0 - k, x1: h.x1 + k, y1: h.y1 + k, r: h.r + k });
|
|
122
|
+
const cushions = [];
|
|
123
|
+
const backs = [];
|
|
124
|
+
for (let i = 0; i < rows; i += 1) {
|
|
125
|
+
const k = (i + 0.5) * step;
|
|
126
|
+
cushions.push(line(k - step * 0.12));
|
|
127
|
+
backs.push(line(k + step * 0.32));
|
|
128
|
+
}
|
|
129
|
+
const gaps = ring.aisles.map(([[x0, y0], [x1, y1]]) => `M${n1(x0)} ${n1(y0)}L${n1(x1)} ${n1(y1)}`).join("");
|
|
130
|
+
return (el("path", { class: "ky-bud-grow", d: cushions.join(""), fill: "none", "stroke-width": num(step * 0.5), "stroke-dasharray": "1.5 .5" }) +
|
|
131
|
+
el("path", { class: "ky-bud-gback", d: backs.join(""), fill: "none", "stroke-width": num(step * 0.16), "stroke-dasharray": "1.5 .5" }) +
|
|
132
|
+
(gaps === "" ? "" : el("path", { class: "ky-bud-gaisle", d: gaps, fill: "none", "stroke-width": 3.4 })));
|
|
133
|
+
}
|
|
108
134
|
const poly = (points) => `M${points.map(([x, y]) => `${Math.round(x)} ${Math.round(y)}`).join("L")}Z`;
|
|
109
135
|
/** The stands and the crowd as markup and the defs it uses. The markup is laid over the ground and under the surface. */
|
|
110
136
|
export function drawCrowd(stands, o) {
|
|
@@ -134,7 +160,10 @@ export function drawCrowd(stands, o) {
|
|
|
134
160
|
// The upper tiers are a little emptier: their paint is the same tile with the empty seats' bed showing through a veil.
|
|
135
161
|
// The bed of seats under the tile, so that no seam of the pattern shows light.
|
|
136
162
|
const bed = stands.gallery === true ? "ky-cr-bed ky-bud-gbed" : "ky-cr-bed";
|
|
137
|
-
|
|
163
|
+
// A hall's gallery, seen from above, is neat rows of seats along its band (a few people are not drawn: it is subtle).
|
|
164
|
+
if (stands.gallery === true && fine)
|
|
165
|
+
body += el("path", { class: bed, d: path(ring) }) + galleryRows(ring) + (density > 0 ? el("path", { class: "ky-cr-people", d: path(ring), fill: `url(#${id}-cr-h)` }) : "");
|
|
166
|
+
else if (fine)
|
|
138
167
|
body += el("path", { class: bed, d: path(ring) }) + el("path", { class: "ky-cr-people", d: path(ring), fill: `url(#${id}-cr-h)` });
|
|
139
168
|
else
|
|
140
169
|
body += el("path", { class: bed, d: path(ring) }) + el("path", { class: stands.gallery === true ? "ky-cr-blk ky-bud-gblk" : "ky-cr-blk", d: path(ring), "fill-opacity": num(0.28 + 0.6 * density * ring.fill) });
|
|
@@ -145,7 +174,7 @@ export function drawCrowd(stands, o) {
|
|
|
145
174
|
body += sector(s, id, fine, density);
|
|
146
175
|
if (fine)
|
|
147
176
|
for (const ring of stands.rings)
|
|
148
|
-
body +=
|
|
177
|
+
body += stands.gallery === true ? "" : rows(ring) + aisles(ring);
|
|
149
178
|
// Depth: the front wall of a tier throws a shade on its first rows (and the ground in front of it), the roof's edge on the last rows of the upper tier.
|
|
150
179
|
// A gallery's railing: a line along its front edge, over the seats.
|
|
151
180
|
if (stands.gallery === true)
|
|
@@ -166,7 +195,7 @@ export function drawCrowd(stands, o) {
|
|
|
166
195
|
const [x0, y0, x1, y1] = g.box;
|
|
167
196
|
body += el("rect", { class: `ky-cr-${g.kind}`, x: n1(x0), y: n1(y0), width: n1(x1 - x0), height: n1(y1 - y0), rx: g.kind === "bench" ? 1 : undefined });
|
|
168
197
|
}
|
|
169
|
-
return { defs: (fine ? patterns(id, crowd, density, tifo.home || tifo.away ? tifo : undefined, stands.gallery === true) : ""), markup: el("g", { class: "ky-crowd" }, body), over };
|
|
198
|
+
return { defs: (fine && (stands.gallery !== true || density > 0) ? patterns(id, crowd, density, tifo.home || tifo.away ? tifo : undefined, stands.gallery === true) : ""), markup: el("g", { class: "ky-crowd" }, body), over };
|
|
170
199
|
}
|
|
171
200
|
/** A block of visitors or a card display, a polygon over the band it is in. */
|
|
172
201
|
function sector(s, id, fine, density) {
|
package/dist/crowd.js
CHANGED
|
@@ -284,6 +284,10 @@ function aislesOf(region, hole) {
|
|
|
284
284
|
}
|
|
285
285
|
return [];
|
|
286
286
|
}
|
|
287
|
+
/** The aisles of a hall's gallery: on each straight side, one across the band at each of the `shares` (0 to 1) of the side's length, from the first side's left end. */
|
|
288
|
+
function galleryAisles(region, hole, shares) {
|
|
289
|
+
return [0, 2, 4, 6].flatMap((side) => shares.map((f) => [rrectAt(hole, side + f).p, rrectAt(region, side + f).p]));
|
|
290
|
+
}
|
|
287
291
|
/** The polygon of a band between two aisle parameters: along the outer edge, then back along the inner. */
|
|
288
292
|
function sectionBetween(region, hole, u0, u1) {
|
|
289
293
|
const us = [u0];
|
|
@@ -341,7 +345,8 @@ export function layoutOf(input) {
|
|
|
341
345
|
rake: Math.round((Math.atan2(rise, Math.max(1, t.to - t.from)) * 180) / Math.PI * 10) / 10,
|
|
342
346
|
fill: t.fill,
|
|
343
347
|
seats: seatsIn(region, hole),
|
|
344
|
-
aisles: aislesOf(region, hole),
|
|
348
|
+
aisles: gal?.aisles !== undefined && region.kind === "rrect" && hole.kind === "rrect" ? galleryAisles(region, hole, gal.aisles) : aislesOf(region, hole),
|
|
349
|
+
...(gal?.rows === undefined ? {} : { rows: gal.rows }),
|
|
345
350
|
});
|
|
346
351
|
reachOf.left = Math.max(reachOf.left, off.left + t.to);
|
|
347
352
|
reachOf.right = Math.max(reachOf.right, off.right + t.to);
|
package/dist/draw.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ballparkDrawn, ballparkFor, ballparkSentences } from "./ballpark.js";
|
|
2
|
-
import { inkOn, safeColour } from "./colour.js";
|
|
2
|
+
import { inkOn, safeColour, safePicture } from "./colour.js";
|
|
3
3
|
import { withEmblems } from "./emblems-source.js";
|
|
4
|
-
import { safeLogo } from "./logo.js";
|
|
4
|
+
import { flagPicture, safeLogo } from "./logo.js";
|
|
5
|
+
import { flagDocument, flagTheme, withFlags } from "./flags-source.js";
|
|
5
6
|
import { drawingId, feetFence, isPortrait, lengthUnit, safeClass } from "./common.js";
|
|
6
7
|
import { el, esc, num } from "./format.js";
|
|
7
8
|
import { fieldAttributes } from "./field.data.js";
|
|
@@ -424,7 +425,7 @@ function standsFor(o, surface, crowd) {
|
|
|
424
425
|
}
|
|
425
426
|
// A dojo's crowd sits in its gallery, from the room's balcony data (in feet here); the arenas (the Budokan, the Kokugikan) keep their bowls.
|
|
426
427
|
const hall = sport === "dojo" ? dojoGallery(o) : undefined;
|
|
427
|
-
const gallery = hall === undefined ? undefined : { offset: hall.offset / 0.3048, depth: hall.depth / 0.3048, height: [hall.height[0] / 0.3048, hall.height[1] / 0.3048] };
|
|
428
|
+
const gallery = hall === undefined ? undefined : { offset: hall.offset / 0.3048, depth: hall.depth / 0.3048, height: [hall.height[0] / 0.3048, hall.height[1] / 0.3048], rows: hall.rows, aisles: hall.aisles };
|
|
428
429
|
return crowdLayout({ sport, box: surface.whole ?? surface.box ?? { x: 0, y: 0, w: 100, h: 100 }, crowd, awaySide, ground: o.ground, arena: o.budo?.hall === "budokan", ...(gallery === undefined ? {} : { gallery }) });
|
|
429
430
|
}
|
|
430
431
|
/** True when the drawing is asked to be small: `detail: "simple"` or a `width` under 480 pixels. */
|
|
@@ -451,8 +452,8 @@ function buildCrowded(o, portrait, id, score, scored, extra, crowd) {
|
|
|
451
452
|
const fine = crowd.detail === "fine" || (crowd.detail === "auto" && !smallDrawing(o));
|
|
452
453
|
const first = /^<[^>]*\/>/.exec(surface.base)?.[0] ?? "";
|
|
453
454
|
const bg = /class="([^"]*)"/.exec(first)?.[1] ?? "ky-apron";
|
|
454
|
-
// A gallery is
|
|
455
|
-
const taken = stands.gallery === true && crowd.density === undefined && crowd.attendance === undefined ? 0
|
|
455
|
+
// A gallery is empty unless the options say how full: its seats are the detail.
|
|
456
|
+
const taken = stands.gallery === true && crowd.density === undefined && crowd.attendance === undefined ? 0 : densityOf(crowd, seats, ground);
|
|
456
457
|
const drawn = drawCrowd(stands, { id, crowd, density: taken, fine, ground: bg });
|
|
457
458
|
surface.base = first + drawn.markup + surface.base.slice(first.length);
|
|
458
459
|
surface.defs += drawn.defs;
|
|
@@ -476,6 +477,9 @@ function colourStyle(o, teams, features) {
|
|
|
476
477
|
if (c !== undefined)
|
|
477
478
|
for (const [key, property] of [["mat", "--ky-surface"], ["alt", "--ky-surface-alt"], ["border", "--ky-red"], ["heri", "--ky-bud-heri"], ["floor", "--ky-bud-floor"], ["wall", "--ky-boards"]])
|
|
478
479
|
set(property, c[key]);
|
|
480
|
+
// A heri the dojo's colours name is drawn as a cloth edge; the stylesheet's own is a faint seam.
|
|
481
|
+
if (safeColour(c?.heri) !== undefined)
|
|
482
|
+
props.push("--ky-bud-hop:.82");
|
|
479
483
|
}
|
|
480
484
|
if (o.court !== undefined)
|
|
481
485
|
for (const [key, property] of Object.entries(COURT_PROPERTIES))
|
|
@@ -531,10 +535,13 @@ function roundOf(team, markShape) {
|
|
|
531
535
|
return undefined;
|
|
532
536
|
return { round: true, fit: team.markFit === "contain" ? "contain" : undefined, color: safeColour(team.color), ink: safeColour(team.textColor) };
|
|
533
537
|
}
|
|
538
|
+
/** The width in pixels a flag is asked for in a team's mark (a nominal one: a drawing scales). */
|
|
539
|
+
const FLAG_MARK_SIZE = 48;
|
|
534
540
|
function teamView(team, side, role, winner, uppercase, sport, markShape, theme) {
|
|
535
541
|
const name = String(team.name ?? "");
|
|
536
542
|
const abbr = (team.abbr !== undefined && team.abbr.trim() !== "" ? team.abbr.trim() : abbreviate(name)).slice(0, 5);
|
|
537
543
|
const written = fieldScoreText(sport, team) ?? budoScoreText(sport, team);
|
|
544
|
+
const round = roundOf(team, markShape);
|
|
538
545
|
const score = written ?? (team.score === undefined || team.score === null || String(team.score).trim() === "" ? "–" : String(team.score));
|
|
539
546
|
return {
|
|
540
547
|
side,
|
|
@@ -542,8 +549,9 @@ function teamView(team, side, role, winner, uppercase, sport, markShape, theme)
|
|
|
542
549
|
name: uppercase ? capitals(name) : name,
|
|
543
550
|
abbr,
|
|
544
551
|
score,
|
|
545
|
-
|
|
546
|
-
|
|
552
|
+
// The flag a team's country code names, when a renderer of flags is plugged in, is its logo: round in a round mark, in its own proportions otherwise.
|
|
553
|
+
logo: flagPicture(team.flag, round === undefined ? "rect" : "round", FLAG_MARK_SIZE, theme) ?? safeLogo(team.logo, { color: team.color, accent: team.textColor, initials: abbr.slice(0, 3), theme }),
|
|
554
|
+
...round,
|
|
547
555
|
state: stateOf(winner, role),
|
|
548
556
|
ends: Array.isArray(team.ends) ? team.ends.map(endText) : undefined,
|
|
549
557
|
hammer: team.hammer === true ? true : undefined,
|
|
@@ -558,22 +566,27 @@ function teamView(team, side, role, winner, uppercase, sport, markShape, theme)
|
|
|
558
566
|
};
|
|
559
567
|
}
|
|
560
568
|
/** A team as the pageant lays it out. */
|
|
561
|
-
function pageantTeam(view, team) {
|
|
562
|
-
|
|
569
|
+
function pageantTeam(view, team, style, theme) {
|
|
570
|
+
// A carpet is a flag laid flat, in its own proportions; a stage is a round disc, so a flag is asked for round there.
|
|
571
|
+
const flag = flagDocument(team.flag, { shape: style === "stage" ? "round" : "rect", size: FLAG_PAGEANT_SIZE, theme: flagTheme(theme) });
|
|
572
|
+
const picture = safePicture(flag);
|
|
573
|
+
return { side: view.side, role: view.role, name: view.name, abbr: view.abbr, state: view.state, href: picture ?? view.logo, fit: team.markFit === "contain" ? "contain" : "cover", ratio: ratioOf({ logo: picture === undefined ? team.logo : flag, logoRatio: team.logoRatio }), color: safeColour(team.color), ink: safeColour(team.textColor) };
|
|
563
574
|
}
|
|
575
|
+
/** The width in pixels a flag is asked for when a pageant lays it out large (a nominal one: a drawing scales). */
|
|
576
|
+
const FLAG_PAGEANT_SIZE = 240;
|
|
564
577
|
/** True when the drawing is asked to be small: its `width` is under 320 pixels. The pageant then leaves out its fabric, hairlines and name pills. */
|
|
565
578
|
function tiny(width) {
|
|
566
579
|
const px = typeof width === "number" ? width : typeof width === "string" && /^\d+(?:\.\d+)?(?:px)?$/.test(width.trim()) ? Number.parseFloat(width) : undefined;
|
|
567
580
|
return px !== undefined && Number.isFinite(px) && px < 320;
|
|
568
581
|
}
|
|
569
582
|
/** The teams that fill the first and the second place of a surface: a diamond's outfield is the visitors' and its infield the home team's, whichever side each is on. */
|
|
570
|
-
function pageantPair(surface, t) {
|
|
571
|
-
const l = pageantTeam(t.left, t.leftTeam);
|
|
572
|
-
const r = pageantTeam(t.right, t.rightTeam);
|
|
583
|
+
function pageantPair(surface, t, style, theme) {
|
|
584
|
+
const l = pageantTeam(t.left, t.leftTeam, style, theme);
|
|
585
|
+
const r = pageantTeam(t.right, t.rightTeam, style, theme);
|
|
573
586
|
return surface.pageant?.byRole === true && l.role === "home" ? [r, l] : [l, r];
|
|
574
587
|
}
|
|
575
588
|
function pageantParts(o, surface, p, t) {
|
|
576
|
-
const [first, second] = pageantPair(surface, t);
|
|
589
|
+
const [first, second] = pageantPair(surface, t, p.style, o.theme);
|
|
577
590
|
const layout = pageantLayout({ pageant: p, surface, outline: outlineOf(o), left: first, right: second, turned: surface.turned, sport: t.sport, plate: t.plate });
|
|
578
591
|
if (layout === undefined)
|
|
579
592
|
return undefined;
|
|
@@ -808,7 +821,7 @@ export function describe(o) {
|
|
|
808
821
|
* ```
|
|
809
822
|
*/
|
|
810
823
|
export function drawKyogijo(o) {
|
|
811
|
-
return withEmblems(o.emblems, () => drawnKyogijo(o));
|
|
824
|
+
return withEmblems(o.emblems, () => withFlags(o.flags, () => drawnKyogijo(o)));
|
|
812
825
|
}
|
|
813
826
|
function drawnKyogijo(o) {
|
|
814
827
|
if (o.host !== undefined && o.range !== undefined)
|
|
@@ -903,7 +916,7 @@ function drawnKyogijo(o) {
|
|
|
903
916
|
if (pageant !== undefined && pageant.score === "auto") {
|
|
904
917
|
let score = stripped ? "strip" : "centre";
|
|
905
918
|
if (!stripped && isScore(o) && left !== undefined && right !== undefined && leftTeam !== undefined && rightTeam !== undefined && sized === "full") {
|
|
906
|
-
const [first, second] = pageantPair(surface, { left, right, leftTeam, rightTeam });
|
|
919
|
+
const [first, second] = pageantPair(surface, { left, right, leftTeam, rightTeam }, pageant.style, o.theme);
|
|
907
920
|
score = autoScore({ pageant, surface, outline: outlineOf(o), left: first, right: second, turned: surface.turned, sport, plate: true });
|
|
908
921
|
}
|
|
909
922
|
pageant = { ...pageant, score };
|
package/dist/element-entry.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { KYOGIJO_ATTRIBUTES, KYOGIJO_TAG, KyogijoField, defineKyogijoField, optionsFromAttributes, replaySettingsFromAttributes, turnSettingsFromAttributes, turnWanted } from "./element.ts";
|
|
2
2
|
export { useEmblems } from "./emblems-source.ts";
|
|
3
3
|
export type { EmblemRenderer } from "./emblems-source.ts";
|
|
4
|
+
export { useFlags } from "./flags-source.ts";
|
|
5
|
+
export type { FlagRenderer, FlagRequest, FlagShape } from "./flags-source.ts";
|
package/dist/element-entry.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
// The custom element's class and its registration function; importing this entry registers nothing.
|
|
2
2
|
export { KYOGIJO_ATTRIBUTES, KYOGIJO_TAG, KyogijoField, defineKyogijoField, optionsFromAttributes, replaySettingsFromAttributes, turnSettingsFromAttributes, turnWanted } from "./element.js";
|
|
3
3
|
export { useEmblems } from "./emblems-source.js";
|
|
4
|
+
export { useFlags } from "./flags-source.js";
|
package/dist/element.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ import type { ScoreOptions, SurfaceOptions } from "./types.ts";
|
|
|
6
6
|
/** The tag of the element. */
|
|
7
7
|
export declare const KYOGIJO_TAG = "kyogijo-field";
|
|
8
8
|
/** The attributes the element reads. */
|
|
9
|
-
export declare const KYOGIJO_ATTRIBUTES: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch"];
|
|
10
|
-
/** The settings of a 3D view an element's attributes make: `turn-view` names the viewpoint it opens on, `turn-controls="false"` and `turn-uprights="false"` leave the buttons and what stands on the surface out, `turn-score="floor"` leaves the score panel on the floor, `turn-touch="turn"` keeps every touch for the view. */
|
|
9
|
+
export declare const KYOGIJO_ATTRIBUTES: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-flag", "away-flag", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed"];
|
|
10
|
+
/** The settings of a 3D view an element's attributes make: `turn-view` names the viewpoint it opens on, `turn-controls="false"` and `turn-uprights="false"` leave the buttons and what stands on the surface out, `turn-score="floor"` leaves the score panel on the floor, `turn-touch="turn"` keeps every touch for the view, `turn-venue="false"` leaves out the stands and the room (they are raised for a drawing with a crowd and for a dojo), `turn-roof` puts a roof or canopy over the stands, `turn-autoplay` starts the auto-turn (`force` even for a reader who prefers reduced motion) and `turn-speed` is its degrees a second. */
|
|
11
11
|
export declare function turnSettingsFromAttributes(read: (name: string) => string | null, base?: TurnSettings): TurnSettings;
|
|
12
12
|
/** Whether an element's `turn` attribute asks for the 3D view: present, and not `false`. */
|
|
13
13
|
export declare const turnWanted: (read: (name: string) => string | null) => boolean;
|
|
@@ -24,7 +24,7 @@ export declare function optionsFromAttributes(read: (name: string) => string | n
|
|
|
24
24
|
declare const Base: typeof HTMLElement;
|
|
25
25
|
export declare class KyogijoField extends Base {
|
|
26
26
|
#private;
|
|
27
|
-
static observedAttributes: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch"];
|
|
27
|
+
static observedAttributes: readonly ["sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase", "pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks", "home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-flag", "away-flag", "home-color", "away-color", "status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options", "loop", "speed", "autoplay", "controls", "trail", "turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed"];
|
|
28
28
|
/** The options given as a property: an object, laid under the attributes. */
|
|
29
29
|
get options(): Partial<ScoreOptions> | undefined;
|
|
30
30
|
set options(value: Partial<ScoreOptions> | undefined);
|
package/dist/element.js
CHANGED
|
@@ -22,14 +22,14 @@ export const KYOGIJO_TAG = "kyogijo-field";
|
|
|
22
22
|
export const KYOGIJO_ATTRIBUTES = [
|
|
23
23
|
"sport", "league", "size", "theme", "language", "orientation", "park", "ground", "arena", "year", "detail", "margin", "stripes", "exact-lines", "uppercase",
|
|
24
24
|
"pitch", "pitch-type", "half", "range", "range-end", "goals", "stripe-pattern", "corner-flags", "look", "line-width", "line-dash", "line-opacity", "landmarks", "walls", "quirks",
|
|
25
|
-
"home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-color", "away-color",
|
|
25
|
+
"home", "away", "home-abbr", "away-abbr", "home-score", "away-score", "home-penalties", "away-penalties", "score", "home-logo", "away-logo", "home-flag", "away-flag", "home-color", "away-color",
|
|
26
26
|
"status", "competition", "date", "label", "winner", "home-side", "pageant", "description", "options",
|
|
27
27
|
"loop", "speed", "autoplay", "controls", "trail",
|
|
28
|
-
"turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch",
|
|
28
|
+
"turn", "turn-view", "turn-controls", "turn-uprights", "turn-score", "turn-touch", "turn-venue", "turn-roof", "turn-autoplay", "turn-speed",
|
|
29
29
|
];
|
|
30
30
|
/** The attributes that are about a replay and not about the drawing. */
|
|
31
31
|
const REPLAY_ATTRIBUTES = ["loop", "speed", "autoplay", "controls", "trail"];
|
|
32
|
-
/** The settings of a 3D view an element's attributes make: `turn-view` names the viewpoint it opens on, `turn-controls="false"` and `turn-uprights="false"` leave the buttons and what stands on the surface out, `turn-score="floor"` leaves the score panel on the floor, `turn-touch="turn"` keeps every touch for the view. */
|
|
32
|
+
/** The settings of a 3D view an element's attributes make: `turn-view` names the viewpoint it opens on, `turn-controls="false"` and `turn-uprights="false"` leave the buttons and what stands on the surface out, `turn-score="floor"` leaves the score panel on the floor, `turn-touch="turn"` keeps every touch for the view, `turn-venue="false"` leaves out the stands and the room (they are raised for a drawing with a crowd and for a dojo), `turn-roof` puts a roof or canopy over the stands, `turn-autoplay` starts the auto-turn (`force` even for a reader who prefers reduced motion) and `turn-speed` is its degrees a second. */
|
|
33
33
|
export function turnSettingsFromAttributes(read, base = {}) {
|
|
34
34
|
const out = { ...base };
|
|
35
35
|
const view = read("turn-view");
|
|
@@ -43,6 +43,20 @@ export function turnSettingsFromAttributes(read, base = {}) {
|
|
|
43
43
|
out.score = "floor";
|
|
44
44
|
if (read("turn-touch") === "turn")
|
|
45
45
|
out.touch = "turn";
|
|
46
|
+
// The venue: off with `false`; `turn-roof` (present, and not `false`) asks for the roof.
|
|
47
|
+
const roof = read("turn-roof") !== null && read("turn-roof") !== "false";
|
|
48
|
+
if (read("turn-venue") === "false")
|
|
49
|
+
out.venue = false;
|
|
50
|
+
else if (roof)
|
|
51
|
+
out.venue = { ...(typeof out.venue === "object" ? out.venue : {}), roof: true };
|
|
52
|
+
const auto = read("turn-autoplay");
|
|
53
|
+
if (auto === "force")
|
|
54
|
+
out.autoPlay = "force";
|
|
55
|
+
else if (auto !== null && auto !== "false")
|
|
56
|
+
out.autoPlay = true;
|
|
57
|
+
const speed = Number(read("turn-speed"));
|
|
58
|
+
if (read("turn-speed") !== null && Number.isFinite(speed))
|
|
59
|
+
out.speed = speed;
|
|
46
60
|
return out;
|
|
47
61
|
}
|
|
48
62
|
/** Whether an element's `turn` attribute asks for the 3D view: present, and not `false`. */
|
|
@@ -215,6 +229,9 @@ export function optionsFromAttributes(read, base) {
|
|
|
215
229
|
const logo = read(`${role}-logo`);
|
|
216
230
|
if (logo !== null)
|
|
217
231
|
out.logo = logo;
|
|
232
|
+
const flag = read(`${role}-flag`);
|
|
233
|
+
if (flag !== null)
|
|
234
|
+
out.flag = flag;
|
|
218
235
|
const color = read(`${role}-color`);
|
|
219
236
|
if (color !== null)
|
|
220
237
|
out.color = color;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** How a flag is framed: `round` for a circle, `square` as wide as it is tall, `rect` in its own proportions. */
|
|
2
|
+
export type FlagShape = "round" | "square" | "rect";
|
|
3
|
+
/** What a drawing asks a `flags` renderer for. */
|
|
4
|
+
export interface FlagRequest {
|
|
5
|
+
shape: FlagShape;
|
|
6
|
+
/** The width in pixels the flag is drawn at, nominally (a drawing scales, so this is the size of a typical use): the diameter of a round flag. */
|
|
7
|
+
size: number;
|
|
8
|
+
/** `light` or `dark` for a drawing in that look, else `inherit`. */
|
|
9
|
+
theme: "inherit" | "light" | "dark";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A function from a country code and a request to an SVG string, or `null` or `undefined` for a code it has no flag for. It must be synchronous: a drawing is a pure function of its
|
|
13
|
+
* options. `@johnmorrisdotca/hata`'s `flag()` is asynchronous, so load the flags first (`await flag(code, { shape: "round" })` for each code) and pass a lookup.
|
|
14
|
+
*/
|
|
15
|
+
export type FlagRenderer = (code: string, request: FlagRequest) => string | null | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Plug a renderer of country flags into kyogijo, for every drawing on the page: after this a team's `flag: "CA"` is drawn. Call it once, at start-up. Without one a team's `flag` is
|
|
18
|
+
* ignored and its `logo` (or its initials) is drawn. `useFlags(undefined)` unplugs it.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { useFlags } from "@johnmorrisdotca/kyogijo-stadiums";
|
|
22
|
+
* const loaded = { round: { CA: "<svg viewBox='0 0 1 1'>...</svg>" } } as Record<string, Record<string, string>>;
|
|
23
|
+
* useFlags((code, { shape }) => loaded[shape]?.[code.toUpperCase()]);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function useFlags(render: FlagRenderer | undefined): void;
|
|
27
|
+
/** Run a drawing with a renderer for that drawing alone (the `flags` option), putting back whatever was there. Without a renderer it runs as it is. */
|
|
28
|
+
export declare function withFlags<T>(render: FlagRenderer | undefined, draw: () => T): T;
|
|
29
|
+
/** The renderer in use: the drawing's own, else the page's, else none. */
|
|
30
|
+
export declare function flagRenderer(): FlagRenderer | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The flag of a country code as an SVG document, drawn by the renderer in use, or `undefined`: no renderer, a value that does not look like a code, a code the renderer has no flag for,
|
|
33
|
+
* a renderer that throws, or one that returns something that is not an `<svg>`. It never throws.
|
|
34
|
+
*/
|
|
35
|
+
export declare function flagDocument(code: unknown, request: FlagRequest): string | undefined;
|
|
36
|
+
/** The theme a drawing tells a renderer: `light` or `dark` when the options say so, else `inherit`. */
|
|
37
|
+
export declare const flagTheme: (theme: unknown) => FlagRequest["theme"];
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Where kyogijo gets country flags from: a renderer that the page plugs in, so that kyogijo bundles no flag and keeps zero dependencies. The renderer is a synchronous function from a
|
|
2
|
+
// country code and a request to an SVG string; `@johnmorrisdotca/hata` draws the flags, and its `flag()` is asynchronous, so a page loads the codes it needs first and plugs in a lookup
|
|
3
|
+
// (docs/flags.md). `useFlags(render)` plugs it in for the page, `flags: render` for one drawing. The shape of the renderer is the one Taisen Brackets takes, so one adapter serves both.
|
|
4
|
+
// This module knows nothing of any flag: it asks the renderer, checks what it gives back, and returns an SVG document or nothing.
|
|
5
|
+
let plugged;
|
|
6
|
+
let scoped;
|
|
7
|
+
/**
|
|
8
|
+
* Plug a renderer of country flags into kyogijo, for every drawing on the page: after this a team's `flag: "CA"` is drawn. Call it once, at start-up. Without one a team's `flag` is
|
|
9
|
+
* ignored and its `logo` (or its initials) is drawn. `useFlags(undefined)` unplugs it.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { useFlags } from "@johnmorrisdotca/kyogijo-stadiums";
|
|
13
|
+
* const loaded = { round: { CA: "<svg viewBox='0 0 1 1'>...</svg>" } } as Record<string, Record<string, string>>;
|
|
14
|
+
* useFlags((code, { shape }) => loaded[shape]?.[code.toUpperCase()]);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function useFlags(render) {
|
|
18
|
+
plugged = typeof render === "function" ? render : undefined;
|
|
19
|
+
}
|
|
20
|
+
/** Run a drawing with a renderer for that drawing alone (the `flags` option), putting back whatever was there. Without a renderer it runs as it is. */
|
|
21
|
+
export function withFlags(render, draw) {
|
|
22
|
+
if (typeof render !== "function")
|
|
23
|
+
return draw();
|
|
24
|
+
const before = scoped;
|
|
25
|
+
scoped = render;
|
|
26
|
+
try {
|
|
27
|
+
return draw();
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
scoped = before;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The renderer in use: the drawing's own, else the page's, else none. */
|
|
34
|
+
export function flagRenderer() {
|
|
35
|
+
return scoped ?? plugged;
|
|
36
|
+
}
|
|
37
|
+
/** The look of a country or region code: letters and digits in one or two parts (`CA`, `usa`, `GB-ENG`, `JP-13`). */
|
|
38
|
+
const CODE = /^[A-Za-z0-9]{2,8}(?:-[A-Za-z0-9]{1,8})?$/;
|
|
39
|
+
/**
|
|
40
|
+
* The flag of a country code as an SVG document, drawn by the renderer in use, or `undefined`: no renderer, a value that does not look like a code, a code the renderer has no flag for,
|
|
41
|
+
* a renderer that throws, or one that returns something that is not an `<svg>`. It never throws.
|
|
42
|
+
*/
|
|
43
|
+
export function flagDocument(code, request) {
|
|
44
|
+
const render = flagRenderer();
|
|
45
|
+
if (render === undefined || typeof code !== "string")
|
|
46
|
+
return undefined;
|
|
47
|
+
const text = code.trim();
|
|
48
|
+
if (!CODE.test(text))
|
|
49
|
+
return undefined;
|
|
50
|
+
let svg;
|
|
51
|
+
try {
|
|
52
|
+
svg = render(text, { shape: request.shape, size: Math.round(request.size), theme: request.theme });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
return typeof svg === "string" && /^\s*(?:<\?xml|<svg)\b/i.test(svg) ? svg : undefined;
|
|
58
|
+
}
|
|
59
|
+
/** The theme a drawing tells a renderer: `light` or `dark` when the options say so, else `inherit`. */
|
|
60
|
+
export const flagTheme = (theme) => (theme === "light" || theme === "dark" ? theme : "inherit");
|
package/dist/halls.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/** The Kodokan's main dojo as drawn: a square floor of 420 jō's area, four contest areas, the seat of honour, the banner, the wood and the gallery, in the two looks the owner's photographs show. The years of both are unknown. */
|
|
2
2
|
const KODOKAN_MAIN = {
|
|
3
3
|
mats: { width: 26.4, length: 26.4 },
|
|
4
|
-
surround:
|
|
4
|
+
surround: 4,
|
|
5
5
|
areas: { across: 2, down: 2 },
|
|
6
6
|
dais: true,
|
|
7
7
|
banner: true,
|
|
8
|
-
|
|
8
|
+
// Per the owner, with his photographs: a gallery of 3 rows of seats on each side, the blocks of a row 5, 8, 8, 8 and 5 seats (34 to a row, 102 to a side) with an aisle between them.
|
|
9
|
+
balcony: { rows: 3, sections: [5, 8, 8, 8, 5] },
|
|
9
10
|
kamiza: "north",
|
|
10
11
|
eras: [
|
|
11
12
|
{ name: "earlier", nameJa: "以前", from: null, to: null, look: "green-orange", outline: true },
|
|
@@ -31,7 +32,7 @@ export const HALLS = Object.freeze([
|
|
|
31
32
|
fromWhat: { en: "founded by Kanō Jigorō (the International Judo Center, the building the dojos are in, was completed in 1984)", ja: "嘉納治五郎が創設(道場のある講道館国際柔道センターは1984年に完成)" },
|
|
32
33
|
leagues: [],
|
|
33
34
|
surfaces: [
|
|
34
|
-
{ id: "main-dojo", name: { en: "Main dojo, 7th floor", ja: "大道場(7階)" }, sport: "dojo", options: { dojo: KODOKAN_MAIN }, basis: "count", mats: 420, note: { en: "420 jō on the 7th floor, four contest areas at once, with a gallery on the 8th that seats about 900. Per the owner's photographs: four contest areas in two rows, pale yellow mats on green safety bands and a green border, on a wood
|
|
35
|
+
{ id: "main-dojo", name: { en: "Main dojo, 7th floor", ja: "大道場(7階)" }, sport: "dojo", options: { dojo: KODOKAN_MAIN }, basis: "count", mats: 420, note: { en: "420 jō on the 7th floor, four contest areas at once, with a gallery on the 8th that seats about 900. Per the owner's photographs: four contest areas in two rows, pale yellow mats on green safety bands and a green border, on a wide wood floor all round (about 4 m, ours), a raised seat of honour with a dark banner at the front wall, a gallery on all four sides. The shape of the floor is not documented: a square of 26.4 m, the area of 420 jō, is drawn so that four areas of 8 m fit. Per the owner and his photographs: the gallery has 3 rows of seats on each side, in blocks of 5, 8, 8, 8 and 5 seats (34 a row, 102 a side) divided by aisles, behind a white rail; the lower wall is honey wood panelling and the upper wall plain off-white.", ja: "7階に420畳、同時に4面の試合ができ、8階に約900人が座れる見学席があります。提供された写真では、試合場が2列に4面並び、淡い黄色の畳の外側を緑の安全地帯と緑の縁取りが囲んでいます。周囲は板張りで、正面の上座には一段高い台と濃い色の垂れ幕があり、四方に見学席があります。床の形は資料にないので、420畳の広さにあたる26.4m四方の床に、8m四方の試合場4面が収まるように描いています。提供者の数え方と写真によると、見学席は各辺3列で、1列は5席・8席・8席・8席・5席のブロック(1列34席、1辺102席)に通路で区切られ、白い手すりの奥に並びます。下の壁は蜂蜜色の板張り、上の壁は無地のオフホワイトです。" } },
|
|
35
36
|
{ id: "main-dojo-earlier", name: { en: "Main dojo, 7th floor (earlier colours)", ja: "大道場(7階・以前の色)" }, sport: "dojo", options: { dojo: { ...KODOKAN_MAIN, era: "earlier" } }, basis: "count", mats: 420, note: { en: "The same room in the colours of the owner's older photograph: all green mats, the four contest areas outlined by red-orange border mats. No source gives the years of either look, so the eras carry none.", ja: "提供された古い写真の色で描いた同じ部屋です。畳はすべて緑で、4面の試合場それぞれを赤橙色の縁の畳が囲んでいます。どちらの色だった時期も資料にないので、年は記していません。" } },
|
|
36
37
|
{ id: "school-dojo", name: { en: "Judo School dojo, 6th floor", ja: "学校道場(6階)" }, sport: "dojo", options: { dojo: { jo: 240, look: "green-beige" } }, basis: "count", mats: 240, note: { en: "240 jō on the 6th floor; the shape is plausible.", ja: "6階に240畳。形は推定です。" } },
|
|
37
38
|
{ id: "international-dojo", name: { en: "International dojo, 6th floor", ja: "国際部道場(6階)" }, sport: "dojo", options: { dojo: { jo: 192, look: "green-beige" } }, basis: "count", mats: 192, note: { en: "192 jō on the 6th floor; the shape is plausible.", ja: "6階に192畳。形は推定です。" } },
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export { inkOn, luminance, rgbOf, safeColour, safePicture } from "./colour.ts";
|
|
|
4
4
|
export { safeLogo } from "./logo.ts";
|
|
5
5
|
export { useEmblems } from "./emblems-source.ts";
|
|
6
6
|
export type { EmblemDrawOptions, EmblemId, EmblemRef, EmblemRenderer, EmblemStyleName } from "./emblems-source.ts";
|
|
7
|
+
export { useFlags } from "./flags-source.ts";
|
|
8
|
+
export type { FlagRenderer, FlagRequest, FlagShape } from "./flags-source.ts";
|
|
7
9
|
export { OUTCOMES, drawLayers, layerTable } from "./layers.ts";
|
|
8
10
|
export { RANGES } from "./ranges.names.ts";
|
|
9
11
|
export { BACKGROUND_OPACITY, BACKGROUND_PATTERNS, KYOGIJO_BACKGROUND_STYLE } from "./background.ts";
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { HOME_FIRST, HOME_FIRST_LEAGUES, homeSideFor } from "./homeside.js";
|
|
|
4
4
|
export { inkOn, luminance, rgbOf, safeColour, safePicture } from "./colour.js";
|
|
5
5
|
export { safeLogo } from "./logo.js";
|
|
6
6
|
export { useEmblems } from "./emblems-source.js";
|
|
7
|
+
export { useFlags } from "./flags-source.js";
|
|
7
8
|
export { OUTCOMES, drawLayers, layerTable } from "./layers.js";
|
|
8
9
|
export { RANGES } from "./ranges.names.js";
|
|
9
10
|
export { BACKGROUND_OPACITY, BACKGROUND_PATTERNS, KYOGIJO_BACKGROUND_STYLE } from "./background.js";
|
package/dist/layers.env.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// What every kind of data layer is drawn against: the drawing's id, its unit and outline, the words, and what a layer made. Kept apart
|
|
2
2
|
// from layers.ts so that the heat maps, which are written in files of their own, can use it without importing the file that imports them.
|
|
3
|
-
import { safeLogo } from "./logo.js";
|
|
3
|
+
import { flagPicture, safeLogo } from "./logo.js";
|
|
4
4
|
import { esc } from "./format.js";
|
|
5
5
|
import { drawingId, isPortrait, lengthUnit } from "./common.js";
|
|
6
6
|
import { fromSurface, toSurface } from "./frames.js";
|
|
@@ -104,7 +104,10 @@ export function envFor(o, turned, range, upright, zone) {
|
|
|
104
104
|
cropped: range !== undefined,
|
|
105
105
|
base: Math.max((range ?? outline.box).w, (range ?? outline.box).h) * 0.013,
|
|
106
106
|
words: KYOGIJO_STRINGS[language],
|
|
107
|
-
logos: {
|
|
107
|
+
logos: {
|
|
108
|
+
home: flagPicture(teams.home?.flag, "rect", 48, o.theme) ?? safeLogo(teams.home?.logo, { color: teams.home?.color, accent: teams.home?.textColor }),
|
|
109
|
+
away: flagPicture(teams.away?.flag, "rect", 48, o.theme) ?? safeLogo(teams.away?.logo, { color: teams.away?.color, accent: teams.away?.textColor }),
|
|
110
|
+
},
|
|
108
111
|
marks: o.marks === true || o.pointer === true,
|
|
109
112
|
zone: zone ?? zonesOf(o),
|
|
110
113
|
};
|
package/dist/layers.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// either is used.
|
|
6
6
|
import { safeColour } from "./colour.js";
|
|
7
7
|
import { withEmblems } from "./emblems-source.js";
|
|
8
|
+
import { withFlags } from "./flags-source.js";
|
|
8
9
|
import { safeLogo } from "./logo.js";
|
|
9
10
|
import { FRAMES } from "./frames.js";
|
|
10
11
|
import { KYOGIJO_HEAT_STYLE, KYOGIJO_TEAM_STYLE } from "./style.js";
|
|
@@ -358,7 +359,7 @@ function summarise(layer, made, words, stop, gap) {
|
|
|
358
359
|
}
|
|
359
360
|
/** The layers of a drawing as markup, and a sentence for each. `turned` says whether the surface group is turned a quarter. */
|
|
360
361
|
export function renderLayers(o, layers, turned, range, upright, zone) {
|
|
361
|
-
return withEmblems(o.emblems, () => renderedLayers(o, layers, turned, range, upright, zone));
|
|
362
|
+
return withEmblems(o.emblems, () => withFlags(o.flags, () => renderedLayers(o, layers, turned, range, upright, zone)));
|
|
362
363
|
}
|
|
363
364
|
function renderedLayers(o, layers, turned, range, upright, zone) {
|
|
364
365
|
if (layers === undefined || layers.length === 0)
|
package/dist/logo.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FlagShape } from "./flags-source.ts";
|
|
1
2
|
/** What a caller says about the team an emblem stands for: its colours and letters, so a crest id takes them; and the theme of the drawing it goes in. */
|
|
2
3
|
export interface EmblemContext {
|
|
3
4
|
color?: string;
|
|
@@ -23,3 +24,8 @@ export declare function emblemDocument(value: unknown, context?: EmblemContext):
|
|
|
23
24
|
* ```
|
|
24
25
|
*/
|
|
25
26
|
export declare function safeLogo(value: unknown, context?: EmblemContext): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The picture of a country's flag as it may be written into an image's `href`, or `undefined` when no renderer of flags is plugged in (`useFlags`, or the `flags` option), it has no flag for the code, or
|
|
29
|
+
* `code` is not a code. `size` is the nominal width in pixels the renderer is told; `theme` is the drawing's.
|
|
30
|
+
*/
|
|
31
|
+
export declare function flagPicture(code: unknown, shape: FlagShape, size: number, theme?: unknown): string | undefined;
|
package/dist/logo.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// (`useEmblems`, or the `emblems` option), the id of one (`"trophy:cup"`, `"crest:shield"`, `"sport:hockey/line"`). The result is an address that may be written into an image's `href`, or `undefined`.
|
|
3
3
|
import { safePicture } from "./colour.js";
|
|
4
4
|
import { GROUPED_ID, emblemRenderer, renderedEmblem } from "./emblems-source.js";
|
|
5
|
+
import { flagDocument, flagTheme } from "./flags-source.js";
|
|
5
6
|
let told = false;
|
|
6
7
|
/** Once, in development: an id with its group was given and nothing is plugged in to draw it. */
|
|
7
8
|
function hint(value) {
|
|
@@ -45,3 +46,10 @@ export function safeLogo(value, context) {
|
|
|
45
46
|
hint(value);
|
|
46
47
|
return picture;
|
|
47
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* The picture of a country's flag as it may be written into an image's `href`, or `undefined` when no renderer of flags is plugged in (`useFlags`, or the `flags` option), it has no flag for the code, or
|
|
51
|
+
* `code` is not a code. `size` is the nominal width in pixels the renderer is told; `theme` is the drawing's.
|
|
52
|
+
*/
|
|
53
|
+
export function flagPicture(code, shape, size, theme) {
|
|
54
|
+
return safePicture(flagDocument(code, { shape, size, theme: flagTheme(theme) }));
|
|
55
|
+
}
|
package/dist/pool.labels.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// split pace bars in the lanes. Drawn in feet in the frame of a pool lying wide; a pool lying tall turns it with the pool, so that the labels lie along the lanes, and only the numbers in the discs are
|
|
3
3
|
// turned back upright. Nothing here is a rule of the sport: the sizes are ours.
|
|
4
4
|
import { safeColour } from "./colour.js";
|
|
5
|
-
import { safeLogo } from "./logo.js";
|
|
5
|
+
import { flagPicture, safeLogo } from "./logo.js";
|
|
6
6
|
import { el, esc, num } from "./format.js";
|
|
7
7
|
import { feet } from "./pool.js";
|
|
8
8
|
import { STATUS_TEXT, formatTime, pacePer100, splitMetres } from "./pool.race.js";
|
|
@@ -45,8 +45,10 @@ function disc(o, cx, cy, text, cls, fill) {
|
|
|
45
45
|
const size = text.length > 2 ? r * 0.95 : r * 1.25;
|
|
46
46
|
return el("circle", { class: cls, cx, cy, r, fill }) + textOn(o.portrait, cx, cy + size * 0.36, text, { size, anchor: "middle", cls: "ky-pl-dn", weight: 800 });
|
|
47
47
|
}
|
|
48
|
+
/** The picture of a swimmer's flag: the `flag` given, else the flag of the `country` code (in its own proportions, by the renderer of flags in use). */
|
|
49
|
+
const flagOf = (row) => safeLogo(row.flag) ?? flagPicture(row.country, "rect", 24);
|
|
48
50
|
function flagMarkup(row, x, cy, w, h) {
|
|
49
|
-
const logo =
|
|
51
|
+
const logo = flagOf(row);
|
|
50
52
|
if (logo === undefined)
|
|
51
53
|
return "";
|
|
52
54
|
return el("image", { class: "ky-logo", href: logo, x, y: cy - h / 2, width: w, height: h, preserveAspectRatio: "xMidYMid slice" }) + el("rect", { class: "ky-pl-fb", x, y: cy - h / 2, width: w, height: h, rx: 0.25, fill: "none" });
|
|
@@ -211,7 +213,7 @@ export function raceArt(plan, o) {
|
|
|
211
213
|
name: show.names ? Math.min(nameMax, Math.max(14, longest)) : 0,
|
|
212
214
|
abbr: show.names ? Math.max(0, ...race.rows.map((r) => tw(r.abbr, SMALL))) : 0,
|
|
213
215
|
seed: show.seeds && race.rows.some((r) => r.seed !== undefined) ? Math.max(...race.rows.map((r) => tw(r.seed ?? "", SMALL * 0.9))) : 0,
|
|
214
|
-
flag: show.flags && race.rows.some((r) =>
|
|
216
|
+
flag: show.flags && race.rows.some((r) => flagOf(r) !== undefined) ? 4.5 : 0,
|
|
215
217
|
};
|
|
216
218
|
let left = "";
|
|
217
219
|
let reachLeft = 0;
|
package/dist/pool.race.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface RaceRow {
|
|
|
18
18
|
name: string;
|
|
19
19
|
abbr: string;
|
|
20
20
|
flag: string | undefined;
|
|
21
|
+
/** The country code of the flag, when the swimmer has one and no `flag` of its own. */
|
|
22
|
+
country: string | undefined;
|
|
21
23
|
color: string | undefined;
|
|
22
24
|
seed: string | undefined;
|
|
23
25
|
/** The final time in seconds and as it is written (a time of text that cannot be read is written as it is). */
|
package/dist/pool.race.js
CHANGED
|
@@ -66,6 +66,7 @@ export function racePlan(race, lanes, defaults) {
|
|
|
66
66
|
name: clean(swimmer.name, 40) ?? "",
|
|
67
67
|
abbr: (clean(swimmer.abbr, 5) ?? "").toLocaleUpperCase("en"),
|
|
68
68
|
flag: typeof swimmer.flag === "string" ? swimmer.flag : undefined,
|
|
69
|
+
country: typeof swimmer.country === "string" ? swimmer.country : undefined,
|
|
69
70
|
color: typeof swimmer.color === "string" ? swimmer.color : undefined,
|
|
70
71
|
seed: typeof swimmer.seed === "number" ? (Number.isFinite(swimmer.seed) ? formatTime(swimmer.seed) : undefined) : clean(swimmer.seed, 12),
|
|
71
72
|
time,
|
package/dist/pool.types.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface Swimmer {
|
|
|
23
23
|
abbr?: string;
|
|
24
24
|
/** The flag or crest, drawn small beside the name. */
|
|
25
25
|
flag?: string;
|
|
26
|
+
/** A country code (`CA`, `jp`) for the flag, drawn by the renderer of flags plugged in with `useFlags` (or the drawing's `flags` option), in its own proportions, where `flag` is missing. */
|
|
27
|
+
country?: string;
|
|
26
28
|
/** The swimmer's colour (a cap, a club), drawn as a stripe on the label. */
|
|
27
29
|
color?: string;
|
|
28
30
|
/** The entry time. */
|