@johnmorrisdotca/kyogijo-stadiums 0.5.0 → 0.6.1

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.
Files changed (193) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/NOTICE.md +179 -3
  3. package/README.md +43 -11
  4. package/dist/arenas-entry.d.ts +4 -0
  5. package/dist/arenas-entry.js +3 -0
  6. package/dist/arenas.d.ts +125 -0
  7. package/dist/arenas.data.d.ts +2 -0
  8. package/dist/arenas.data.js +3763 -0
  9. package/dist/arenas.js +72 -0
  10. package/dist/atlas-entry.d.ts +3 -1
  11. package/dist/atlas-entry.js +3 -2
  12. package/dist/atlas.d.ts +37 -19
  13. package/dist/atlas.js +92 -7
  14. package/dist/background.js +2 -1
  15. package/dist/budo/describe.d.ts +13 -0
  16. package/dist/budo/describe.js +120 -0
  17. package/dist/budo/dojo.api.d.ts +64 -0
  18. package/dist/budo/dojo.api.js +46 -0
  19. package/dist/budo/dojo.d.ts +72 -0
  20. package/dist/budo/dojo.js +300 -0
  21. package/dist/budo/judo.d.ts +61 -0
  22. package/dist/budo/judo.js +109 -0
  23. package/dist/budo/karate.d.ts +29 -0
  24. package/dist/budo/karate.js +80 -0
  25. package/dist/budo/kendo.d.ts +18 -0
  26. package/dist/budo/kendo.js +44 -0
  27. package/dist/budo/kimarite.d.ts +19 -0
  28. package/dist/budo/kimarite.js +33 -0
  29. package/dist/budo/kit.d.ts +16 -0
  30. package/dist/budo/kit.js +24 -0
  31. package/dist/budo/kyudo.d.ts +28 -0
  32. package/dist/budo/kyudo.js +66 -0
  33. package/dist/budo/looks.d.ts +28 -0
  34. package/dist/budo/looks.js +58 -0
  35. package/dist/budo/parts.d.ts +32 -0
  36. package/dist/budo/parts.js +10 -0
  37. package/dist/budo/plan.d.ts +64 -0
  38. package/dist/budo/plan.js +139 -0
  39. package/dist/budo/room.d.ts +133 -0
  40. package/dist/budo/room.js +111 -0
  41. package/dist/budo/sumo.d.ts +31 -0
  42. package/dist/budo/sumo.js +71 -0
  43. package/dist/budo/tatami.d.ts +55 -0
  44. package/dist/budo/tatami.js +156 -0
  45. package/dist/budo/types.d.ts +192 -0
  46. package/dist/budo/types.js +2 -0
  47. package/dist/budo-entry.d.ts +22 -0
  48. package/dist/budo-entry.js +13 -0
  49. package/dist/budo.board.d.ts +28 -0
  50. package/dist/budo.board.js +81 -0
  51. package/dist/budo.score.d.ts +18 -0
  52. package/dist/budo.score.js +52 -0
  53. package/dist/budo.style.d.ts +6 -0
  54. package/dist/budo.style.js +67 -0
  55. package/dist/charts.baseball.js +1 -1
  56. package/dist/charts.js +4 -4
  57. package/dist/charts.soccer.js +3 -3
  58. package/dist/charts.types.d.ts +10 -0
  59. package/dist/colour.d.ts +4 -4
  60. package/dist/colour.js +4 -4
  61. package/dist/crowd.d.ts +11 -1
  62. package/dist/crowd.draw.js +15 -9
  63. package/dist/crowd.js +17 -2
  64. package/dist/draw.js +156 -31
  65. package/dist/element-entry.d.ts +2 -0
  66. package/dist/element-entry.js +1 -0
  67. package/dist/element.d.ts +2 -2
  68. package/dist/element.js +2 -1
  69. package/dist/emblems-source.d.ts +50 -0
  70. package/dist/emblems-source.js +56 -0
  71. package/dist/eras.d.ts +3 -1
  72. package/dist/eras.js +8 -3
  73. package/dist/features.js +73 -0
  74. package/dist/field.data.d.ts +16 -0
  75. package/dist/field.data.js +50 -0
  76. package/dist/fields.kit.d.ts +2 -2
  77. package/dist/fields.types.d.ts +9 -3
  78. package/dist/formations.js +18 -7
  79. package/dist/formations.sports.d.ts +8 -0
  80. package/dist/formations.sports.js +251 -0
  81. package/dist/frames.providers.js +9 -1
  82. package/dist/halls.d.ts +65 -0
  83. package/dist/halls.js +122 -0
  84. package/dist/heat.js +17 -10
  85. package/dist/heat.zones.d.ts +4 -2
  86. package/dist/heat.zones.js +55 -3
  87. package/dist/homeside.js +7 -0
  88. package/dist/index.d.ts +15 -3
  89. package/dist/index.js +8 -1
  90. package/dist/layers-entry.d.ts +2 -1
  91. package/dist/layers-entry.js +1 -0
  92. package/dist/layers.d.ts +2 -1
  93. package/dist/layers.env.d.ts +10 -1
  94. package/dist/layers.env.js +33 -3
  95. package/dist/layers.js +30 -11
  96. package/dist/layers.types.d.ts +9 -2
  97. package/dist/leagues/budo.d.ts +196 -0
  98. package/dist/leagues/budo.js +105 -0
  99. package/dist/leagues/hockey.js +41 -19
  100. package/dist/leagues/sources.js +21 -0
  101. package/dist/leagues/types.d.ts +1 -1
  102. package/dist/leagues.d.ts +4 -1
  103. package/dist/leagues.js +102 -2
  104. package/dist/lineup.codes.d.ts +23 -0
  105. package/dist/lineup.codes.js +122 -0
  106. package/dist/logo.d.ts +25 -0
  107. package/dist/logo.js +47 -0
  108. package/dist/outline.d.ts +1 -1
  109. package/dist/outline.js +17 -3
  110. package/dist/pageant.js +7 -3
  111. package/dist/pointer-entry.d.ts +2 -0
  112. package/dist/pointer-entry.js +2 -0
  113. package/dist/pointer.d.ts +113 -0
  114. package/dist/pointer.js +151 -0
  115. package/dist/pool.d.ts +7 -7
  116. package/dist/pool.figures.d.ts +57 -55
  117. package/dist/pool.figures.js +59 -55
  118. package/dist/pool.js +7 -7
  119. package/dist/pool.labels.js +2 -1
  120. package/dist/ranges.names.js +6 -0
  121. package/dist/road.draw.js +3 -2
  122. package/dist/road.js +2 -1
  123. package/dist/road.types.d.ts +3 -0
  124. package/dist/rules.d.ts +138 -0
  125. package/dist/rules.js +511 -0
  126. package/dist/rules.types.d.ts +4 -0
  127. package/dist/rules.types.js +64 -0
  128. package/dist/score.d.ts +3 -0
  129. package/dist/score.js +23 -1
  130. package/dist/situation.d.ts +135 -0
  131. package/dist/situation.draw.d.ts +34 -0
  132. package/dist/situation.draw.js +202 -0
  133. package/dist/situation.js +337 -0
  134. package/dist/situation.style.d.ts +2 -0
  135. package/dist/situation.style.js +45 -0
  136. package/dist/situation.types.d.ts +77 -0
  137. package/dist/situation.types.js +3 -0
  138. package/dist/situation.widgets.d.ts +39 -0
  139. package/dist/situation.widgets.js +129 -0
  140. package/dist/strings.d.ts +175 -1
  141. package/dist/strings.js +364 -20
  142. package/dist/style.js +9 -2
  143. package/dist/surfaces/artistic.d.ts +3 -3
  144. package/dist/surfaces/artistic.js +3 -3
  145. package/dist/surfaces/baseball.js +2 -0
  146. package/dist/surfaces/basketball.js +1 -1
  147. package/dist/surfaces/budo.d.ts +6 -0
  148. package/dist/surfaces/budo.js +104 -0
  149. package/dist/surfaces/dive.d.ts +3 -3
  150. package/dist/surfaces/dive.js +3 -3
  151. package/dist/surfaces/football.js +7 -0
  152. package/dist/surfaces/hockey.js +3 -2
  153. package/dist/surfaces/polo.d.ts +4 -4
  154. package/dist/surfaces/polo.js +5 -5
  155. package/dist/surfaces/pool.d.ts +1 -1
  156. package/dist/surfaces/pool.js +3 -3
  157. package/dist/surfaces/surface.d.ts +32 -0
  158. package/dist/surfaces/venue.d.ts +1 -1
  159. package/dist/surfaces/venue.js +1 -1
  160. package/dist/target-entry.d.ts +2 -0
  161. package/dist/target-entry.js +2 -0
  162. package/dist/target.d.ts +200 -0
  163. package/dist/target.js +525 -0
  164. package/dist/team.common.d.ts +1 -1
  165. package/dist/team.common.js +3 -3
  166. package/dist/team.formation.d.ts +3 -1
  167. package/dist/team.formation.js +3 -3
  168. package/dist/team.layers.d.ts +2 -2
  169. package/dist/team.layers.js +4 -1
  170. package/dist/team.lineup.d.ts +27 -0
  171. package/dist/team.lineup.js +207 -0
  172. package/dist/team.network.js +6 -5
  173. package/dist/team.shape.js +5 -5
  174. package/dist/team.types.d.ts +40 -1
  175. package/dist/tenants.data.js +848 -0
  176. package/dist/turn-entry.d.ts +2 -2
  177. package/dist/turn-entry.js +1 -1
  178. package/dist/turn.camera.d.ts +16 -3
  179. package/dist/turn.camera.js +53 -7
  180. package/dist/turn.dom.js +11 -9
  181. package/dist/turn.kit.d.ts +2 -2
  182. package/dist/turn.style.js +4 -3
  183. package/dist/types.d.ts +43 -7
  184. package/dist/units.js +7 -0
  185. package/dist/uprights.budo.d.ts +17 -0
  186. package/dist/uprights.budo.js +87 -0
  187. package/dist/uprights.js +10 -1
  188. package/dist/uprights.pools.js +4 -4
  189. package/dist/version.d.ts +1 -1
  190. package/dist/version.js +1 -1
  191. package/dist/zones-entry.d.ts +2 -0
  192. package/dist/zones-entry.js +2 -0
  193. package/package.json +39 -3
package/dist/arenas.js ADDED
@@ -0,0 +1,72 @@
1
+ import { ARENA_DATA } from "./arenas.data.js";
2
+ import { officialName, placesNamed } from "./names.js";
3
+ const FEET_PER_METRE = 1 / 0.3048;
4
+ const tenth = (feet) => Math.round(feet * 10) / 10;
5
+ const inFeet = (size) => {
6
+ const k = size.unit === "m" ? FEET_PER_METRE : 1;
7
+ return { length: tenth(size.length * k), width: tenth(size.width * k) };
8
+ };
9
+ /** The size that held in a year: the one whose years cover it, else (with no year) the latest. */
10
+ const sizeIn = (sizes, year) => {
11
+ if (sizes === undefined || sizes.length === 0)
12
+ return undefined;
13
+ if (year === undefined || !Number.isFinite(year))
14
+ return inFeet(sizes.find((size) => size.to === undefined) ?? sizes[sizes.length - 1]);
15
+ const found = sizes.find((size) => (size.from === undefined || size.from <= year) && (size.to === undefined || year <= size.to));
16
+ return found === undefined ? undefined : inFeet(found);
17
+ };
18
+ /**
19
+ * The size of an arena's rink in feet, in a year or today (the latest), when the sources publish one that differs from the NHL's; else `undefined` and the NHL's 200 by 85 feet
20
+ * is the rink.
21
+ * @example
22
+ * ```ts
23
+ * import { arenaById, arenaRinkIn } from "@johnmorrisdotca/kyogijo-stadiums/arenas";
24
+ * console.log(arenaRinkIn(arenaById("boston-garden")!), arenaRinkIn(arenaById("matthews-arena")!, 1926), arenaRinkIn(arenaById("td-garden")!));
25
+ * // { length: 190.9, width: 83 } { length: 220, width: 90 } undefined
26
+ * ```
27
+ */
28
+ export const arenaRinkIn = (arena, year) => sizeIn(arena?.rink, year);
29
+ /** The size of an arena's court in feet, in a year or today, when the sources publish one that differs from the NBA's 94 by 50 feet; else `undefined`. */
30
+ export const arenaCourtIn = (arena, year) => sizeIn(arena?.court, year);
31
+ /**
32
+ * Every arena by its key: the homes of the NHL's, the NBA's, the WNBA's and the PWHL's clubs, today's and the old ones, each with where it stands, when it was in use, its names,
33
+ * its seats for each sport and, where the sources publish one that differs from the league's, the size of its rink or its court.
34
+ * @example
35
+ * ```ts
36
+ * import { ARENAS } from "@johnmorrisdotca/kyogijo-stadiums/arenas";
37
+ * const garden = ARENAS["boston-garden"];
38
+ * console.log(garden.name, garden.city, garden.from, garden.to, garden.capacity?.hockey);
39
+ * // Boston Garden Boston 1928 1995 14448
40
+ * ```
41
+ */
42
+ export const ARENAS = Object.freeze(Object.fromEntries(ARENA_DATA.map((data) => [data.id, data])));
43
+ /** The keys of `ARENAS`, in the order of the data: the arenas in use first, then those of the past. */
44
+ export const ARENA_IDS = Object.freeze(ARENA_DATA.map((data) => data.id));
45
+ /** The arena with a key, or `undefined`. */
46
+ export const arenaById = (id) => (id !== undefined && Object.prototype.hasOwnProperty.call(ARENAS, id) ? ARENAS[id] : undefined);
47
+ /** The arenas that answer to a name, best match first (see `placesByName`): the everyday names, then the official and cited names, then the former names and the nicknames. */
48
+ export const arenasByName = (name) => placesNamed(Object.values(ARENAS), name);
49
+ /** The arena a name belongs to (the best match when several answer to it), or `undefined`. */
50
+ export const arenaByName = (name) => arenasByName(name)[0];
51
+ /** The arena whose Wikidata item is `Q894567`, or `undefined`. */
52
+ export const arenaByWikidata = (wikidata) => Object.values(ARENAS).find((arena) => arena.wikidata === wikidata);
53
+ /** The name an arena had in a year (the name of the time in English; in Japanese there is one name for every year). */
54
+ export function arenaNameIn(arena, year, language = "en") {
55
+ if (language === "ja")
56
+ return arena.nameJa;
57
+ if (year === undefined || !Number.isFinite(year))
58
+ return arena.name;
59
+ const periods = (arena.names ?? []).filter((period) => period.from <= year && year <= period.to);
60
+ return periods.length === 0 ? arena.name : periods[periods.length - 1].name;
61
+ }
62
+ /** The name an arena officially has in a language, when it is not the everyday name; else `undefined`. */
63
+ export function arenaOfficialName(arena, language = "en", year) {
64
+ const shown = arenaNameIn(arena, year, language);
65
+ if (year !== undefined && Number.isFinite(year) && language === "en" && shown !== arena.name)
66
+ return undefined;
67
+ return officialName(arena, language, shown, Number.isFinite(year) ? year : undefined);
68
+ }
69
+ /** The address of the revision of an article that an arena's facts were read from. */
70
+ export function arenaSourceUrl(source, language = "en") {
71
+ return `https://${language}.wikipedia.org/w/index.php?title=${encodeURIComponent(source.title.replace(/ /g, "_"))}&oldid=${source.revision}`;
72
+ }
@@ -1,4 +1,6 @@
1
- export { PLACES, atlasFacets, placeById, placeByName, placesBy, placesByClub, placesByName, surfaceOf, surfacesOf, tenantsOf } from "./atlas.ts";
1
+ export { PLACES, atlasFacets, hallSurfaces, placeById, placeByName, placesBy, placesByClub, placesByName, surfaceOf, surfacesOf, tenantsOf } from "./atlas.ts";
2
+ export { HALLS } from "./halls.ts";
3
+ export type { Hall, HallBasis, HallSurface } from "./halls.ts";
2
4
  export { officialName, plainName } from "./names.ts";
3
5
  export { TENANTS, TENANT_JAPANESE_NAMES, nameJaOf } from "./tenants.ts";
4
6
  export type { PlaceAlias, PlaceNameKind } from "./names.ts";
@@ -1,4 +1,5 @@
1
- // The atlas: every ballpark and soccer ground with where it stands, when it was in use and the clubs that played there, and the filters over them.
2
- export { PLACES, atlasFacets, placeById, placeByName, placesBy, placesByClub, placesByName, surfaceOf, surfacesOf, tenantsOf } from "./atlas.js";
1
+ // The atlas: every ballpark, soccer ground and hockey and basketball arena, and the famous halls of the budō, with where it stands, when it was in use and the clubs that played there, and the filters over them.
2
+ export { PLACES, atlasFacets, hallSurfaces, placeById, placeByName, placesBy, placesByClub, placesByName, surfaceOf, surfacesOf, tenantsOf } from "./atlas.js";
3
+ export { HALLS } from "./halls.js";
3
4
  export { officialName, plainName } from "./names.js";
4
5
  export { TENANTS, TENANT_JAPANESE_NAMES, nameJaOf } from "./tenants.js";
package/dist/atlas.d.ts CHANGED
@@ -1,9 +1,11 @@
1
+ import { type Hall, type HallSurface } from "./halls.ts";
1
2
  import type { PlaceAlias } from "./names.ts";
3
+ import type { BudoSport, BudoStyle, DojoSpec } from "./types.ts";
2
4
  import type { Tenant, TenantSport } from "./tenants.ts";
3
- /** What a place is: a ballpark (of `PARKS`) or a soccer ground (of `GROUNDS`). */
4
- export type PlaceKind = "park" | "ground";
5
- /** The sport a place is drawn for: baseball parks have a fence, soccer grounds a pitch. */
6
- export type PlaceSport = "baseball" | "soccer";
5
+ /** What a place is: a ballpark (of `PARKS`), a soccer ground (of `GROUNDS`), a hall of the budō (of `HALLS`: a dojo, an arena, a sumo hall) or a hockey and basketball arena (of `ARENAS`). */
6
+ export type PlaceKind = "park" | "ground" | "hall" | "arena";
7
+ /** The sport a place is drawn for: baseball parks have a fence, soccer grounds a pitch, the halls of the budō (`budo`) the mats, the dohyō or the range of their sports, and arenas an ice rink (`hockey`) and a court (`basketball`). */
8
+ export type PlaceSport = "baseball" | "soccer" | "budo" | "hockey" | "basketball";
7
9
  /** `current` is a ground a club or a competition uses today, `past` one it has left, closed or pulled down. */
8
10
  export type PlaceStatus = "current" | "past";
9
11
  /** One place on the atlas: a ballpark or a soccer ground, with where it is and when it was in use. */
@@ -28,7 +30,10 @@ export interface Place {
28
30
  from: number;
29
31
  to: number;
30
32
  }[];
33
+ /** The sport it is first drawn for: a park's is baseball, a ground's soccer, an arena's hockey where an ice hockey club played there, else basketball. */
31
34
  sport: PlaceSport;
35
+ /** Every sport it is drawn for: a park's and a ground's is its `sport` alone, an arena's is `hockey`, `basketball` or both (`TD Garden`), by the clubs that played there. */
36
+ sports: readonly PlaceSport[];
32
37
  /** The leagues and competitions it is known for: the leagues of the park's club and of every club that has played its home matches there (`CFL` and `MLS` for BC Place, `MLB` and `CFL` for Montreal's Olympic Stadium), then the World Cups it staged (`FIFA World Cup`, `FIFA Women's World Cup`). A ground with no tenant that staged none has none. */
33
38
  leagues: readonly string[];
34
39
  /** The clubs that play, or played, their home matches there, with the league and the years of each (see `tenantsOf`): the current ones first. A place no club is known to have called home has none. */
@@ -36,7 +41,7 @@ export interface Place {
36
41
  /** ISO 3166-1 alpha-2: `US`. */
37
42
  country: string;
38
43
  city: string;
39
- /** The club that plays in a park (`Boston Red Sox`); soccer grounds have none (see `tenants`). */
44
+ /** The club that plays in a park (`Boston Red Sox`); soccer grounds and arenas have none (see `tenants`). */
40
45
  team?: string;
41
46
  /** Wikidata's coordinates (P625, CC0), in degrees. */
42
47
  lat: number;
@@ -48,11 +53,14 @@ export interface Place {
48
53
  to?: number;
49
54
  /** The Wikidata item (`Q49136`): the key to join a place to other data. */
50
55
  wikidata: string;
56
+ /** A hall of the budō (`kind: "hall"`): what it holds, how it came to be and the surfaces it offers (see `HALLS`). */
57
+ hall?: Hall;
51
58
  /** True where Wikidata lists athletics among the sports of a soccer ground: a running track lies round its pitch (`drawKyogijo({ sport: "athletics", ground })`). Absent where Wikidata says nothing of it. */
52
59
  track?: boolean;
53
60
  }
54
61
  /** What `placesBy` keeps: every field given must match. A list matches any of its members. */
55
62
  export interface PlaceFilter {
63
+ /** A sport a place is drawn for: an arena is found by `hockey` and by `basketball` if clubs of both played there. */
56
64
  sport?: PlaceSport | readonly PlaceSport[];
57
65
  kind?: PlaceKind | readonly PlaceKind[];
58
66
  /** A league or competition from `Place.leagues`: a tenant's league (`CFL`) or a tournament. */
@@ -65,17 +73,6 @@ export interface PlaceFilter {
65
73
  /** Words to find in any name (the everyday names, the aliases, the readings), the city or the club, or the name of a club that plays or played there (in English or in Japanese), ignoring case, accents, width and, in Japanese, hiragana or katakana; every word must be found. */
66
74
  text?: string;
67
75
  }
68
- /**
69
- * Every place the package draws, parks first and then grounds, each in the order of its own list: the ballparks of
70
- * `PARKS` and the soccer grounds of `GROUNDS`, with where each stands.
71
- * @example
72
- * ```ts
73
- * import { PLACES } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
74
- * const fenway = PLACES.find((place) => place.id === "fenway-park");
75
- * console.log(fenway?.name, fenway?.lat, fenway?.lon, fenway?.country);
76
- * // Fenway Park 42.34639 -71.0975 US
77
- * ```
78
- */
79
76
  export declare const PLACES: readonly Place[];
80
77
  /** The place with a key, or `undefined`. */
81
78
  export declare const placeById: (id: string | undefined) => Place | undefined;
@@ -122,25 +119,43 @@ export interface AtlasFacets {
122
119
  * import { atlasFacets } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
123
120
  * const { sports, leagues, countries, years } = atlasFacets();
124
121
  * console.log(sports.join(), leagues.length, leagues.includes("CFL"), countries.length, years.min);
125
- * // baseball,soccer 83 true 23 1877
122
+ * // baseball,basketball,budo,hockey,soccer 90 true 23 1877
126
123
  * ```
127
124
  */
128
125
  export declare function atlasFacets(): AtlasFacets;
129
126
  /** The options `drawKyogijo` takes to draw a surface a place offers. */
130
127
  export type PlaceSurface = {
128
+ sport: BudoSport;
129
+ league?: string;
130
+ budo?: BudoStyle;
131
+ dojo?: DojoSpec;
132
+ } | {
131
133
  sport: "mlb";
132
134
  park: string;
133
135
  } | {
134
136
  sport: "soccer";
135
137
  ground?: string;
136
138
  } | {
137
- sport: "nfl" | "cfl" | "nba" | "nhl" | "afl" | "cricket";
139
+ sport: "nhl" | "nba";
140
+ arena?: string;
141
+ } | {
142
+ sport: "nfl" | "cfl" | "afl" | "cricket";
138
143
  } | {
139
144
  sport: "rugby";
140
145
  league?: "nrl";
141
146
  };
142
147
  /** The sports `surfaceOf` can be asked for. */
143
148
  export type SurfaceSport = PlaceSurface["sport"];
149
+ /**
150
+ * Every surface a hall of the budō offers, each with its name, how much of it is documented (`basis`) and the options that draw it, in the order of the hall's own list. A place that is not a hall has none.
151
+ * @example
152
+ * ```ts
153
+ * import { hallSurfaces, placeById } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
154
+ * console.log(hallSurfaces(placeById("kodokan")!).map((surface) => `${surface.id} ${surface.mats}`).join());
155
+ * // main-dojo 420,main-dojo-earlier 420,school-dojo 240,international-dojo 192,womens-dojo 240,boys-dojo 114
156
+ * ```
157
+ */
158
+ export declare const hallSurfaces: (place: Place) => readonly HallSurface[];
144
159
  /**
145
160
  * Every surface a place offers, the place's own first: a park's fence (`mlb` with the park) or a ground's pitch at its size (`soccer` with the ground), then one for each
146
161
  * sport a tenant plays that the package draws (a CFL field for BC Place, an NFL field for MetLife Stadium, the rugby league field for Stadium Australia), each once. A ground
@@ -171,7 +186,10 @@ export declare function surfaceOf(place: Place): {
171
186
  } | {
172
187
  sport: "soccer";
173
188
  ground: string;
174
- };
189
+ } | {
190
+ sport: "nhl" | "nba";
191
+ arena: string;
192
+ } | PlaceSurface;
175
193
  export declare function surfaceOf(place: Place, sport: SurfaceSport): PlaceSurface | undefined;
176
194
  /** What `tenantsOf` keeps: every field given must match. */
177
195
  export interface TenantFilter {
package/dist/atlas.js CHANGED
@@ -1,4 +1,6 @@
1
+ import { ARENAS, ARENA_IDS } from "./arenas.js";
1
2
  import { GROUNDS, GROUND_IDS } from "./grounds.js";
3
+ import { HALLS } from "./halls.js";
2
4
  import { nameContainsAll, placesNamed, plainName } from "./names.js";
3
5
  import { PARKS, PARK_IDS } from "./parks.js";
4
6
  import { SURFACE_OF_SPORT, TENANTS, hasSurface, leaguesOf, playedIn } from "./tenants.js";
@@ -24,6 +26,7 @@ const fromPark = (park) => {
24
26
  ...(park.localName === undefined ? {} : { localName: park.localName, localLanguage: park.localLanguage }),
25
27
  aliases: park.aliases ?? [],
26
28
  sport: "baseball",
29
+ sports: ["baseball"],
27
30
  leagues: withoutRepeats([park.league], leaguesOf(tenants)),
28
31
  tenants,
29
32
  country: park.country,
@@ -48,6 +51,7 @@ const fromGround = (ground) => ({
48
51
  aliases: ground.aliases ?? [],
49
52
  ...(ground.names === undefined ? {} : { names: ground.names }),
50
53
  sport: "soccer",
54
+ sports: ["soccer"],
51
55
  leagues: withoutRepeats(leaguesOf(TENANTS[ground.id] ?? []), leaguesOfGround(ground)),
52
56
  tenants: TENANTS[ground.id] ?? [],
53
57
  country: ground.country,
@@ -60,9 +64,44 @@ const fromGround = (ground) => ({
60
64
  wikidata: ground.wikidata,
61
65
  ...(ground.track === true ? { track: true } : {}),
62
66
  });
67
+ /** The sports an arena is drawn for, by the clubs that played there: hockey first when any ice hockey club did. */
68
+ const sportsOfArena = (tenants) => {
69
+ const out = [];
70
+ if (tenants.some((tenant) => tenant.sport === "ice-hockey" && hasSurface(tenant)))
71
+ out.push("hockey");
72
+ if (tenants.some((tenant) => tenant.sport === "basketball" && hasSurface(tenant)))
73
+ out.push("basketball");
74
+ return out;
75
+ };
76
+ const fromArena = (arena) => {
77
+ const tenants = TENANTS[arena.id] ?? [];
78
+ const sports = sportsOfArena(tenants);
79
+ return {
80
+ id: arena.id,
81
+ kind: "arena",
82
+ name: arena.name,
83
+ nameJa: arena.nameJa,
84
+ ...(arena.readingJa === undefined ? {} : { readingJa: arena.readingJa }),
85
+ ...(arena.localName === undefined ? {} : { localName: arena.localName, localLanguage: arena.localLanguage }),
86
+ aliases: arena.aliases ?? [],
87
+ ...(arena.names === undefined ? {} : { names: arena.names }),
88
+ sport: sports[0] ?? "hockey",
89
+ sports: sports.length === 0 ? ["hockey"] : sports,
90
+ leagues: leaguesOf(tenants),
91
+ tenants,
92
+ country: arena.country,
93
+ city: arena.city,
94
+ lat: arena.lat,
95
+ lon: arena.lon,
96
+ status: arena.status,
97
+ ...(arena.from === undefined ? {} : { from: arena.from }),
98
+ ...(arena.status === "past" && arena.to !== undefined ? { to: arena.to } : {}),
99
+ wikidata: arena.wikidata,
100
+ };
101
+ };
63
102
  /**
64
- * Every place the package draws, parks first and then grounds, each in the order of its own list: the ballparks of
65
- * `PARKS` and the soccer grounds of `GROUNDS`, with where each stands.
103
+ * Every place the package draws, parks first, then grounds, then arenas, each in the order of its own list: the ballparks of
104
+ * `PARKS`, the soccer grounds of `GROUNDS` and the hockey and basketball arenas of `ARENAS`, with where each stands.
66
105
  * @example
67
106
  * ```ts
68
107
  * import { PLACES } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
@@ -71,7 +110,27 @@ const fromGround = (ground) => ({
71
110
  * // Fenway Park 42.34639 -71.0975 US
72
111
  * ```
73
112
  */
74
- export const PLACES = Object.freeze([...PARK_IDS.map((id) => fromPark(PARKS[id])), ...GROUND_IDS.map((id) => fromGround(GROUNDS[id]))]);
113
+ const fromHall = (hall) => ({
114
+ id: hall.id,
115
+ kind: "hall",
116
+ name: hall.name,
117
+ nameJa: hall.nameJa,
118
+ ...(hall.readingJa === undefined ? {} : { readingJa: hall.readingJa }),
119
+ aliases: hall.aliases,
120
+ sport: "budo",
121
+ sports: ["budo"],
122
+ leagues: hall.leagues,
123
+ tenants: [],
124
+ country: hall.country,
125
+ city: hall.city,
126
+ lat: hall.lat,
127
+ lon: hall.lon,
128
+ status: "current",
129
+ from: hall.from,
130
+ wikidata: hall.wikidata,
131
+ hall,
132
+ });
133
+ export const PLACES = Object.freeze([...PARK_IDS.map((id) => fromPark(PARKS[id])), ...GROUND_IDS.map((id) => fromGround(GROUNDS[id])), ...HALLS.map(fromHall), ...ARENA_IDS.map((id) => fromArena(ARENAS[id]))]);
75
134
  const BY_ID = new Map(PLACES.map((place) => [place.id, place]));
76
135
  /** The place with a key, or `undefined`. */
77
136
  export const placeById = (id) => (id === undefined ? undefined : BY_ID.get(id));
@@ -110,7 +169,7 @@ export function placesBy(filter = {}) {
110
169
  const year = filter.year !== undefined && Number.isFinite(filter.year) ? filter.year : undefined;
111
170
  const words = filter.text === undefined ? [] : filter.text.split(/\s+/).map(plain).filter(Boolean);
112
171
  return PLACES.filter((place) => {
113
- if (sports !== undefined && !sports.includes(place.sport))
172
+ if (sports !== undefined && !place.sports.some((sport) => sports.includes(sport)))
114
173
  return false;
115
174
  if (kinds !== undefined && !kinds.includes(place.kind))
116
175
  return false;
@@ -139,7 +198,7 @@ export function placesBy(filter = {}) {
139
198
  * import { atlasFacets } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
140
199
  * const { sports, leagues, countries, years } = atlasFacets();
141
200
  * console.log(sports.join(), leagues.length, leagues.includes("CFL"), countries.length, years.min);
142
- * // baseball,soccer 83 true 23 1877
201
+ * // baseball,basketball,budo,hockey,soccer 90 true 23 1877
143
202
  * ```
144
203
  */
145
204
  export function atlasFacets() {
@@ -151,6 +210,20 @@ export function atlasFacets() {
151
210
  years: { min: Math.min(...years), max: Math.max(...years) },
152
211
  };
153
212
  }
213
+ /** The rink (`hockey`) or the court (`basketball`) of an arena, drawn at the arena's own size where the data has one. */
214
+ const arenaSurface = (place, sport) => ({ sport: sport === "basketball" ? "nba" : "nhl", arena: place.id });
215
+ /** The options that draw a surface of a hall. */
216
+ const hallOptions = (surface) => ({ sport: surface.sport, ...surface.options });
217
+ /**
218
+ * Every surface a hall of the budō offers, each with its name, how much of it is documented (`basis`) and the options that draw it, in the order of the hall's own list. A place that is not a hall has none.
219
+ * @example
220
+ * ```ts
221
+ * import { hallSurfaces, placeById } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
222
+ * console.log(hallSurfaces(placeById("kodokan")!).map((surface) => `${surface.id} ${surface.mats}`).join());
223
+ * // main-dojo 420,main-dojo-earlier 420,school-dojo 240,international-dojo 192,womens-dojo 240,boys-dojo 114
224
+ * ```
225
+ */
226
+ export const hallSurfaces = (place) => (place.kind === "hall" ? (place.hall?.surfaces ?? []) : []);
154
227
  /**
155
228
  * Every surface a place offers, the place's own first: a park's fence (`mlb` with the park) or a ground's pitch at its size (`soccer` with the ground), then one for each
156
229
  * sport a tenant plays that the package draws (a CFL field for BC Place, an NFL field for MetLife Stadium, the rugby league field for Stadium Australia), each once. A ground
@@ -163,8 +236,15 @@ export function atlasFacets() {
163
236
  * ```
164
237
  */
165
238
  export function surfacesOf(place) {
166
- const own = place.kind === "park" ? { sport: "mlb", park: place.id } : { sport: "soccer", ground: place.id };
239
+ if (place.kind === "hall")
240
+ return (place.hall?.surfaces ?? []).map(hallOptions);
241
+ // An arena's surfaces are its rink and its court, each at the arena's own size where the sources publish one.
242
+ const own = place.kind === "park" ? { sport: "mlb", park: place.id } : place.kind === "arena" ? arenaSurface(place, place.sport) : { sport: "soccer", ground: place.id };
167
243
  const out = [own];
244
+ if (place.kind === "arena")
245
+ for (const sport of place.sports)
246
+ if (sport !== place.sport)
247
+ out.push(arenaSurface(place, sport));
168
248
  for (const tenant of place.tenants) {
169
249
  const drawn = SURFACE_OF_SPORT[tenant.sport];
170
250
  if (drawn === undefined || !hasSurface(tenant))
@@ -172,6 +252,9 @@ export function surfacesOf(place) {
172
252
  // A baseball club's fence is a park's: a ground has none to draw.
173
253
  if (drawn.sport === "mlb")
174
254
  continue;
255
+ // An arena's rink and court are already offered, at its size.
256
+ if (place.kind === "arena" && (drawn.sport === "nhl" || drawn.sport === "nba"))
257
+ continue;
175
258
  const surface = drawn.sport === "soccer" ? { sport: "soccer" } : drawn.sport === "rugby" ? { sport: "rugby", ...(drawn.league === undefined ? {} : { league: drawn.league }) } : { sport: drawn.sport };
176
259
  if (out.some((have) => have.sport === surface.sport && (have.sport !== "rugby" || have.league === surface.league)))
177
260
  continue;
@@ -180,8 +263,10 @@ export function surfacesOf(place) {
180
263
  return out;
181
264
  }
182
265
  export function surfaceOf(place, sport) {
266
+ if (place.kind === "hall")
267
+ return sport === undefined ? surfacesOf(place)[0] : surfacesOf(place).find((surface) => surface.sport === sport);
183
268
  if (sport === undefined)
184
- return place.kind === "park" ? { sport: "mlb", park: place.id } : { sport: "soccer", ground: place.id };
269
+ return place.kind === "park" ? { sport: "mlb", park: place.id } : place.kind === "arena" ? arenaSurface(place, place.sport) : { sport: "soccer", ground: place.id };
185
270
  return surfacesOf(place).find((surface) => surface.sport === sport);
186
271
  }
187
272
  /**
@@ -1,7 +1,8 @@
1
1
  // The ground behind a drawing: a subtle pattern drawn in SVG (felt, grass, wood, ice, paper, a grid, dots) and, when the caller has one, a photograph at an opacity. It is
2
2
  // written once here for the drawing (`background` in the options, laid on the apron under the surface) and for a grid of drawings (`drawGrid`, laid under all of them).
3
3
  // Every pattern is a few shapes in a tile, with no random number, in the ink or the line colour of the drawing at a low opacity, so that it follows light and dark.
4
- import { safeColour, safeLogo } from "./colour.js";
4
+ import { safeColour } from "./colour.js";
5
+ import { safeLogo } from "./logo.js";
5
6
  import { el, num } from "./format.js";
6
7
  /** The patterns, in the order a menu lists them. */
7
8
  export const BACKGROUND_PATTERNS = ["felt", "grass", "wood", "ice", "paper", "grid", "dots"];
@@ -0,0 +1,13 @@
1
+ import type { Language, SurfaceOptions, Team } from "../types.ts";
2
+ import type { DojoFigures } from "../leagues/budo.ts";
3
+ import { type BudoPlan } from "./plan.ts";
4
+ type Opt = Pick<SurfaceOptions, "sport" | "league" | "budo" | "dojo" | "range" | "detail">;
5
+ /** The sentence about the surface, as a fragment: "a judo contest area of 10 by 10 metres in a safety area 4 metres wide...". */
6
+ export declare function budoAbout(o: Opt, language: Language, plan?: BudoPlan): string;
7
+ /** The sentences that follow it: what the options mark. Each starts after a gap. */
8
+ export declare function budoSentences(o: Opt, language: Language, plan?: BudoPlan): string;
9
+ /** The mat of a dojo league, for a caller that wants its size in words. */
10
+ export declare const dojoMat: (f: DojoFigures) => string;
11
+ /** What each side scored, in sentences, for a judo, karate, kendo or sumo score: the counts the board shows. Each starts after a gap. */
12
+ export declare function budoScoreSentences(sport: string, order: readonly Pick<Team, "name" | "budo">[], language: Language): string;
13
+ export {};
@@ -0,0 +1,120 @@
1
+ // What a budō drawing says of itself: its sentence about the surface, and what the options mark on it. Built from the plan, so that the words and the drawing agree.
2
+ import { fill, KYOGIJO_STRINGS } from "../strings.js";
3
+ import { budoView } from "../budo.score.js";
4
+ import { kimariteName } from "./kimarite.js";
5
+ import { budoPlan } from "./plan.js";
6
+ const trim = (n) => String(Math.round(n * 100) / 100);
7
+ const cm = (n) => String(Math.round(n * 1000) / 10);
8
+ /** The sentence about the surface, as a fragment: "a judo contest area of 10 by 10 metres in a safety area 4 metres wide...". */
9
+ export function budoAbout(o, language, plan = budoPlan(o)) {
10
+ const words = KYOGIJO_STRINGS[language].budo;
11
+ const mat = (m) => fill(words.tatami, { length: trim(m.length), width: trim(m.width) });
12
+ if (plan.judo !== undefined) {
13
+ const L = plan.judo;
14
+ const c = L.contests[0];
15
+ const contest = trim(c.x1 - c.x0);
16
+ const safety = trim(c.x0);
17
+ const tatami = mat(L.mat);
18
+ if (plan.league === "ijf-kata")
19
+ return fill(words.judoKata, { contest, safety, tatami });
20
+ return L.contests.length > 1 ? fill(words.judoMany, { areas: L.contests.length, contest, safety, gap: trim(L.gap), tatami }) : fill(words.judo, { contest, safety, tatami });
21
+ }
22
+ if (plan.karate !== undefined) {
23
+ const L = plan.karate;
24
+ const area = trim(L.areas[0].x1 - L.areas[0].x0);
25
+ const safety = trim(L.areas[0].x0);
26
+ if (plan.league === "wkf-kata")
27
+ return fill(words.karateKata, { area, safety });
28
+ return L.areas.length > 1 ? fill(words.karateMany, { areas: L.areas.length, area, gap: trim(L.gap), safety }) : fill(words.karate, { area, safety });
29
+ }
30
+ if (plan.kendo !== undefined)
31
+ return fill(words.kendo, { side: trim(plan.kendo.side) });
32
+ if (plan.sumo !== undefined) {
33
+ const L = plan.sumo;
34
+ const fig = plan.figures;
35
+ const bare = !L.parts.areas.some((a) => a.id === "tawara");
36
+ return fill(bare ? words.sumoBare : words.sumo, { platform: trim(fig.platform), height: cm(L.height), circle: trim(fig.circle), count: fig.tawara.count });
37
+ }
38
+ if (plan.kyudo !== undefined) {
39
+ const L = plan.kyudo;
40
+ const fig = plan.figures;
41
+ return fill(plan.league === "enteki" ? words.kyudoEnteki : words.kyudo, { n: L.shooters, distance: trim(fig.distance) });
42
+ }
43
+ const L = plan.dojo;
44
+ if (L === undefined)
45
+ return "";
46
+ const template = L.pattern === "competition" ? words.dojoCompetition : L.pattern === "checker" ? words.dojoChecker : L.pattern === "border" ? words.dojoBorder : words.dojoTraditional;
47
+ return fill(template, { jo: trim(L.jo), width: trim(L.width), length: trim(L.length), mat: fill(words.tatami, { length: trim(L.mat.length), width: trim(L.mat.width) }) });
48
+ }
49
+ /** The sentences that follow it: what the options mark. Each starts after a gap. */
50
+ export function budoSentences(o, language, plan = budoPlan(o)) {
51
+ const words = KYOGIJO_STRINGS[language].budo;
52
+ const { gap } = KYOGIJO_STRINGS[language].said;
53
+ const out = [];
54
+ if (plan.judo !== undefined) {
55
+ const L = plan.judo;
56
+ const fig = plan.figures;
57
+ if (L.danger > 0)
58
+ out.push(words.danger);
59
+ if (o.budo?.platform === true)
60
+ out.push(words.platform);
61
+ if (plan.shapes.some((s) => s.kind === "bar" && s.feature.startsWith("start")) && fig.marks !== null)
62
+ out.push(fill(words.start, { apart: trim(2 * fig.marks.fromCentre) }));
63
+ if (o.budo?.officials === true)
64
+ out.push(words.officials);
65
+ }
66
+ if (plan.karate !== undefined && plan.areas.some((a) => a.feature === "judges" || a.feature === "referee"))
67
+ out.push(words.karateOfficials);
68
+ if (plan.sumo !== undefined && plan.areas.some((a) => a.feature === "tassels"))
69
+ out.push(words.tassels);
70
+ if (plan.dojo !== undefined) {
71
+ const L = plan.dojo;
72
+ out.push(fill(words.dojoKamiza, { side: words.sides[L.kamiza] }));
73
+ if (L.dais !== undefined)
74
+ out.push(words.dojoDais);
75
+ if (L.banner !== undefined)
76
+ out.push(words.dojoBanner);
77
+ if (L.shrine !== undefined)
78
+ out.push(words.dojoShinzen);
79
+ if (L.contests.length > 0)
80
+ out.push(fill(words.dojoAreas, { n: L.contests.length }));
81
+ }
82
+ return out.map((t) => `${gap}${t}`).join("");
83
+ }
84
+ /** The mat of a dojo league, for a caller that wants its size in words. */
85
+ export const dojoMat = (f) => `${trim(f.mat.length)} × ${trim(f.mat.width)} m`;
86
+ /** What each side scored, in sentences, for a judo, karate, kendo or sumo score: the counts the board shows. Each starts after a gap. */
87
+ export function budoScoreSentences(sport, order, language) {
88
+ const words = KYOGIJO_STRINGS[language].budo;
89
+ const { gap } = KYOGIJO_STRINGS[language].said;
90
+ const sep = KYOGIJO_STRINGS[language].layers.listSep;
91
+ const out = [];
92
+ for (const team of order) {
93
+ const v = budoView(team.budo);
94
+ if (v === undefined)
95
+ continue;
96
+ const list = [];
97
+ const count = (n, label) => {
98
+ if (n !== undefined && n > 0)
99
+ list.push(language === "ja" ? `${label}${n}` : `${n} ${label.toLowerCase()}`);
100
+ };
101
+ if (sport === "judo" || sport === "karate") {
102
+ count(v.ippon, words.board.ippon);
103
+ count(v.wazaari, words.board.wazaari);
104
+ count(v.yuko, words.board.yuko);
105
+ count(v.shido, sport === "judo" ? words.board.shido : words.board.chui);
106
+ if (v.senshu === true)
107
+ list.push(words.board.senshu);
108
+ if (list.length > 0)
109
+ out.push(fill(sport === "judo" ? words.board.judoScore : words.board.karateScore, { name: team.name, list: list.join(sep) }));
110
+ }
111
+ else if (sport === "kendo" && v.techniques !== undefined) {
112
+ const named = v.techniques.map((t) => words.board.techniques[t] ?? t);
113
+ out.push(fill(words.board.kendoScore, { name: team.name, list: named.join(sep) }));
114
+ }
115
+ else if (sport === "sumo" && v.kimarite !== undefined) {
116
+ out.push(fill(words.board.sumoScore, { name: team.name, kimarite: kimariteName(v.kimarite, language) }));
117
+ }
118
+ }
119
+ return out.map((t) => `${gap}${t}`).join("");
120
+ }
@@ -0,0 +1,64 @@
1
+ import type { SurfaceOptions } from "../types.ts";
2
+ import type { MBox } from "./parts.ts";
3
+ import type { Piece } from "./tatami.ts";
4
+ import type { Compass, DojoPattern, DojoSpec } from "./types.ts";
5
+ /** One mat of a dojo's floor, or a part of one, in metres from the floor's top left corner. */
6
+ export type Tatami = Piece;
7
+ /** A dojo made from a spec: the floor as data. */
8
+ export interface Dojo {
9
+ /** The spec it was made from. */
10
+ spec: DojoSpec;
11
+ /** The mat standard: a league of the `dojo` sport (`chukyoma`, `kyoma`, `edoma`, `danchima`, `judo-2x1`) and the mat's size in metres. */
12
+ standard: string;
13
+ mat: {
14
+ length: number;
15
+ width: number;
16
+ };
17
+ /** The floor in metres: its width (x, the longer side) and its length (y). */
18
+ width: number;
19
+ length: number;
20
+ /** The floor's area in jō: the area over the area of a mat, a half mat counting a half. */
21
+ jo: number;
22
+ /** How many whole mats, half mats (hanjō) and cut pieces the floor holds. */
23
+ counts: {
24
+ full: number;
25
+ half: number;
26
+ cut: number;
27
+ };
28
+ pattern: DojoPattern;
29
+ /** Every mat, in metres, with the tone it is painted in (1, 2 or 3). */
30
+ mats: readonly Tatami[];
31
+ /** The seat of honour's wall, and the doors and windows with where each is. */
32
+ kamiza: Compass;
33
+ entrances: readonly {
34
+ wall: Compass;
35
+ box: MBox;
36
+ }[];
37
+ windows: readonly {
38
+ wall: Compass;
39
+ box: MBox;
40
+ }[];
41
+ shrine: MBox | undefined;
42
+ /** The thickness of the walls round the floor, 0 for none. */
43
+ wall: number;
44
+ /** The contest areas laid on the floor, in metres. */
45
+ contests: readonly MBox[];
46
+ /** The options that draw it: `drawKyogijo(dojo.options)`. */
47
+ options: SurfaceOptions;
48
+ }
49
+ /**
50
+ * A dojo (道場): the floor in mats, laid as real tatami units, with the walls, doors, windows, shrine and kamiza. `mats` is the floor: a number is its area in jō (8, 12, 20, 50, 100 and 200 give the usual shapes), `[across, along]`
51
+ * the whole mats across and along, `{ width, length, unit }` a size in metres, feet, mats or jō; `pattern` is how it is laid (`traditional`: no four corners meet; `competition`, `checker`, `border`).
52
+ * @example
53
+ * ```ts
54
+ * import { dojo } from "@johnmorrisdotca/kyogijo-stadiums/budo";
55
+ * const d = dojo({ jo: 20 });
56
+ * console.log(d.jo, d.width.toFixed(2), d.length.toFixed(2), d.counts.full, d.counts.half, d.pattern);
57
+ * // 20 7.28 4.55 18 4 traditional
58
+ * ```
59
+ */
60
+ export declare function dojo(spec?: DojoSpec): Dojo;
61
+ /** Draw a dojo: `drawKyogijo` with the spec as the options' `dojo`, and any other option the caller gives. */
62
+ export declare function drawDojo(spec?: DojoSpec, more?: Partial<SurfaceOptions>): string;
63
+ /** The mat standards a dojo can be laid with. */
64
+ export declare const DOJO_STANDARDS: readonly string[];
@@ -0,0 +1,46 @@
1
+ // The dojo builder's public face: `dojo(spec)` lays a floor of tatami out as real units and returns it as plain data (every mat, the floor in metres and in jō, where the kamiza, the doors and the windows are),
2
+ // and `drawDojo(spec)` draws it. The same spec always gives the same floor.
3
+ import { drawKyogijo } from "../draw.js";
4
+ import { DOJO_LEAGUES } from "../leagues/budo.js";
5
+ import { dojoLayout, dojoLeague } from "./dojo.js";
6
+ /**
7
+ * A dojo (道場): the floor in mats, laid as real tatami units, with the walls, doors, windows, shrine and kamiza. `mats` is the floor: a number is its area in jō (8, 12, 20, 50, 100 and 200 give the usual shapes), `[across, along]`
8
+ * the whole mats across and along, `{ width, length, unit }` a size in metres, feet, mats or jō; `pattern` is how it is laid (`traditional`: no four corners meet; `competition`, `checker`, `border`).
9
+ * @example
10
+ * ```ts
11
+ * import { dojo } from "@johnmorrisdotca/kyogijo-stadiums/budo";
12
+ * const d = dojo({ jo: 20 });
13
+ * console.log(d.jo, d.width.toFixed(2), d.length.toFixed(2), d.counts.full, d.counts.half, d.pattern);
14
+ * // 20 7.28 4.55 18 4 traditional
15
+ * ```
16
+ */
17
+ export function dojo(spec = {}) {
18
+ const standard = spec.standard ?? "chukyoma";
19
+ const league = dojoLeague(standard);
20
+ const L = dojoLayout(spec, league);
21
+ return {
22
+ spec,
23
+ standard,
24
+ mat: { length: L.mat.length, width: L.mat.width },
25
+ width: L.width,
26
+ length: L.length,
27
+ jo: L.jo,
28
+ counts: L.counts,
29
+ pattern: L.pattern,
30
+ mats: L.pieces,
31
+ kamiza: L.kamiza,
32
+ entrances: L.entrances,
33
+ windows: L.windows,
34
+ shrine: L.shrine,
35
+ wall: L.wall,
36
+ contests: L.contests,
37
+ options: { sport: "dojo", ...(standard === "chukyoma" ? {} : { league: standard }), dojo: spec },
38
+ };
39
+ }
40
+ /** Draw a dojo: `drawKyogijo` with the spec as the options' `dojo`, and any other option the caller gives. */
41
+ export function drawDojo(spec = {}, more = {}) {
42
+ const d = dojo(spec);
43
+ return drawKyogijo({ ...d.options, ...more, sport: "dojo", dojo: spec });
44
+ }
45
+ /** The mat standards a dojo can be laid with. */
46
+ export const DOJO_STANDARDS = DOJO_LEAGUES.map((l) => l.id);