@johnmorrisdotca/kyogijo-stadiums 0.0.0-stage → 0.4.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.
Files changed (321) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +293 -0
  4. package/README.md +600 -2
  5. package/dist/annotate.d.ts +47 -0
  6. package/dist/annotate.js +349 -0
  7. package/dist/atlas-entry.d.ts +4 -0
  8. package/dist/atlas-entry.js +3 -0
  9. package/dist/atlas.d.ts +131 -0
  10. package/dist/atlas.js +149 -0
  11. package/dist/background.d.ts +56 -0
  12. package/dist/background.js +127 -0
  13. package/dist/ballpark.d.ts +48 -0
  14. package/dist/ballpark.js +129 -0
  15. package/dist/canvas-entry.d.ts +2 -0
  16. package/dist/canvas-entry.js +2 -0
  17. package/dist/canvas.d.ts +85 -0
  18. package/dist/canvas.js +279 -0
  19. package/dist/charts-entry.d.ts +10 -0
  20. package/dist/charts-entry.js +8 -0
  21. package/dist/charts.baseball.d.ts +30 -0
  22. package/dist/charts.baseball.js +152 -0
  23. package/dist/charts.curling.d.ts +52 -0
  24. package/dist/charts.curling.js +196 -0
  25. package/dist/charts.d.ts +172 -0
  26. package/dist/charts.js +508 -0
  27. package/dist/charts.network.d.ts +66 -0
  28. package/dist/charts.network.js +64 -0
  29. package/dist/charts.soccer.d.ts +43 -0
  30. package/dist/charts.soccer.js +191 -0
  31. package/dist/charts.types.d.ts +396 -0
  32. package/dist/charts.types.js +1 -0
  33. package/dist/colour.d.ts +29 -0
  34. package/dist/colour.js +97 -0
  35. package/dist/common.d.ts +14 -0
  36. package/dist/common.js +32 -0
  37. package/dist/court.d.ts +89 -0
  38. package/dist/court.js +248 -0
  39. package/dist/courts.style.d.ts +20 -0
  40. package/dist/courts.style.js +54 -0
  41. package/dist/cricket.board.d.ts +18 -0
  42. package/dist/cricket.board.js +67 -0
  43. package/dist/curling.board.d.ts +24 -0
  44. package/dist/curling.board.js +147 -0
  45. package/dist/d3-entry.d.ts +3 -0
  46. package/dist/d3-entry.js +2 -0
  47. package/dist/d3.d.ts +45 -0
  48. package/dist/d3.js +56 -0
  49. package/dist/draw.d.ts +52 -0
  50. package/dist/draw.js +705 -0
  51. package/dist/element-define.d.ts +2 -0
  52. package/dist/element-define.js +4 -0
  53. package/dist/element-entry.d.ts +1 -0
  54. package/dist/element-entry.js +2 -0
  55. package/dist/element.d.ts +39 -0
  56. package/dist/element.js +321 -0
  57. package/dist/eras-entry.d.ts +2 -0
  58. package/dist/eras-entry.js +2 -0
  59. package/dist/eras.d.ts +204 -0
  60. package/dist/eras.js +396 -0
  61. package/dist/events-entry.d.ts +3 -0
  62. package/dist/events-entry.js +3 -0
  63. package/dist/events.d.ts +54 -0
  64. package/dist/events.data.d.ts +59 -0
  65. package/dist/events.data.js +297 -0
  66. package/dist/events.js +127 -0
  67. package/dist/features.d.ts +31 -0
  68. package/dist/features.js +284 -0
  69. package/dist/field.score.d.ts +5 -0
  70. package/dist/field.score.js +33 -0
  71. package/dist/fields/afl.d.ts +11 -0
  72. package/dist/fields/afl.js +103 -0
  73. package/dist/fields/cricket.d.ts +9 -0
  74. package/dist/fields/cricket.js +81 -0
  75. package/dist/fields/fieldhockey.d.ts +6 -0
  76. package/dist/fields/fieldhockey.js +81 -0
  77. package/dist/fields/gaelic.d.ts +10 -0
  78. package/dist/fields/gaelic.js +86 -0
  79. package/dist/fields/handball.d.ts +6 -0
  80. package/dist/fields/handball.js +85 -0
  81. package/dist/fields/lacrosse.d.ts +17 -0
  82. package/dist/fields/lacrosse.js +169 -0
  83. package/dist/fields/rugby.d.ts +10 -0
  84. package/dist/fields/rugby.js +130 -0
  85. package/dist/fields.d.ts +12 -0
  86. package/dist/fields.js +44 -0
  87. package/dist/fields.kit.d.ts +63 -0
  88. package/dist/fields.kit.js +108 -0
  89. package/dist/fields.style.d.ts +4 -0
  90. package/dist/fields.style.js +19 -0
  91. package/dist/fields.types.d.ts +155 -0
  92. package/dist/fields.types.js +1 -0
  93. package/dist/format.d.ts +10 -0
  94. package/dist/format.js +28 -0
  95. package/dist/formations.d.ts +18 -0
  96. package/dist/formations.js +211 -0
  97. package/dist/frames-entry.d.ts +8 -0
  98. package/dist/frames-entry.js +7 -0
  99. package/dist/frames.d.ts +199 -0
  100. package/dist/frames.js +271 -0
  101. package/dist/frames.providers.d.ts +16 -0
  102. package/dist/frames.providers.js +302 -0
  103. package/dist/geojson-entry.d.ts +2 -0
  104. package/dist/geojson-entry.js +2 -0
  105. package/dist/geojson.d.ts +79 -0
  106. package/dist/geojson.js +147 -0
  107. package/dist/geometry-entry.d.ts +7 -0
  108. package/dist/geometry-entry.js +5 -0
  109. package/dist/geometry.d.ts +295 -0
  110. package/dist/geometry.js +361 -0
  111. package/dist/grounds-entry.d.ts +4 -0
  112. package/dist/grounds-entry.js +3 -0
  113. package/dist/grounds.d.ts +134 -0
  114. package/dist/grounds.data.d.ts +2 -0
  115. package/dist/grounds.data.js +1849 -0
  116. package/dist/grounds.js +74 -0
  117. package/dist/heat.colour.d.ts +37 -0
  118. package/dist/heat.colour.js +54 -0
  119. package/dist/heat.d.ts +43 -0
  120. package/dist/heat.js +614 -0
  121. package/dist/heat.stats.d.ts +123 -0
  122. package/dist/heat.stats.js +413 -0
  123. package/dist/heat.types.d.ts +145 -0
  124. package/dist/heat.types.js +1 -0
  125. package/dist/heat.zones.d.ts +54 -0
  126. package/dist/heat.zones.js +424 -0
  127. package/dist/homeside.d.ts +16 -0
  128. package/dist/homeside.js +43 -0
  129. package/dist/index.d.ts +47 -0
  130. package/dist/index.js +29 -0
  131. package/dist/layers-entry.d.ts +19 -0
  132. package/dist/layers-entry.js +11 -0
  133. package/dist/layers.d.ts +41 -0
  134. package/dist/layers.env.d.ts +72 -0
  135. package/dist/layers.env.js +79 -0
  136. package/dist/layers.js +533 -0
  137. package/dist/layers.marks.d.ts +45 -0
  138. package/dist/layers.marks.js +168 -0
  139. package/dist/layers.types.d.ts +226 -0
  140. package/dist/layers.types.js +1 -0
  141. package/dist/layout.d.ts +97 -0
  142. package/dist/layout.js +381 -0
  143. package/dist/layout.style.d.ts +6 -0
  144. package/dist/layout.style.js +17 -0
  145. package/dist/layouts-entry.d.ts +5 -0
  146. package/dist/layouts-entry.js +4 -0
  147. package/dist/leagues/aussie.d.ts +57 -0
  148. package/dist/leagues/aussie.js +36 -0
  149. package/dist/leagues/baseball.d.ts +58 -0
  150. package/dist/leagues/baseball.js +171 -0
  151. package/dist/leagues/basketball.d.ts +67 -0
  152. package/dist/leagues/basketball.js +128 -0
  153. package/dist/leagues/courts.d.ts +212 -0
  154. package/dist/leagues/courts.js +114 -0
  155. package/dist/leagues/cricket.d.ts +45 -0
  156. package/dist/leagues/cricket.js +34 -0
  157. package/dist/leagues/curling.d.ts +64 -0
  158. package/dist/leagues/curling.js +53 -0
  159. package/dist/leagues/fieldhockey.d.ts +48 -0
  160. package/dist/leagues/fieldhockey.js +29 -0
  161. package/dist/leagues/fields.d.ts +10 -0
  162. package/dist/leagues/fields.js +6 -0
  163. package/dist/leagues/football.d.ts +8 -0
  164. package/dist/leagues/football.js +82 -0
  165. package/dist/leagues/gaelic.d.ts +50 -0
  166. package/dist/leagues/gaelic.js +29 -0
  167. package/dist/leagues/handball.d.ts +45 -0
  168. package/dist/leagues/handball.js +32 -0
  169. package/dist/leagues/hockey.d.ts +63 -0
  170. package/dist/leagues/hockey.js +166 -0
  171. package/dist/leagues/lacrosse.d.ts +103 -0
  172. package/dist/leagues/lacrosse.js +175 -0
  173. package/dist/leagues/rugby.d.ts +59 -0
  174. package/dist/leagues/rugby.js +72 -0
  175. package/dist/leagues/sources.d.ts +18 -0
  176. package/dist/leagues/sources.js +95 -0
  177. package/dist/leagues/types.d.ts +43 -0
  178. package/dist/leagues/types.js +5 -0
  179. package/dist/leagues-entry.d.ts +23 -0
  180. package/dist/leagues-entry.js +15 -0
  181. package/dist/leagues.d.ts +172 -0
  182. package/dist/leagues.js +462 -0
  183. package/dist/look.d.ts +50 -0
  184. package/dist/look.js +186 -0
  185. package/dist/mark.d.ts +35 -0
  186. package/dist/mark.js +59 -0
  187. package/dist/mount-entry.d.ts +2 -0
  188. package/dist/mount-entry.js +2 -0
  189. package/dist/mount.d.ts +63 -0
  190. package/dist/mount.js +167 -0
  191. package/dist/mow.d.ts +36 -0
  192. package/dist/mow.js +111 -0
  193. package/dist/names.d.ts +77 -0
  194. package/dist/names.js +97 -0
  195. package/dist/outline.d.ts +25 -0
  196. package/dist/outline.js +112 -0
  197. package/dist/parks-entry.d.ts +4 -0
  198. package/dist/parks-entry.js +3 -0
  199. package/dist/parks.d.ts +200 -0
  200. package/dist/parks.data.d.ts +2 -0
  201. package/dist/parks.data.js +4489 -0
  202. package/dist/parks.js +92 -0
  203. package/dist/plot-entry.d.ts +2 -0
  204. package/dist/plot-entry.js +2 -0
  205. package/dist/plot.d.ts +74 -0
  206. package/dist/plot.js +68 -0
  207. package/dist/png-entry.d.ts +2 -0
  208. package/dist/png-entry.js +2 -0
  209. package/dist/png.d.ts +26 -0
  210. package/dist/png.js +46 -0
  211. package/dist/ranges.d.ts +33 -0
  212. package/dist/ranges.js +178 -0
  213. package/dist/ranges.names.d.ts +31 -0
  214. package/dist/ranges.names.js +65 -0
  215. package/dist/react-entry.d.ts +2 -0
  216. package/dist/react-entry.js +2 -0
  217. package/dist/react.d.ts +53 -0
  218. package/dist/react.js +58 -0
  219. package/dist/replay-entry.d.ts +5 -0
  220. package/dist/replay-entry.js +4 -0
  221. package/dist/replay.control.d.ts +47 -0
  222. package/dist/replay.control.js +184 -0
  223. package/dist/replay.d.ts +170 -0
  224. package/dist/replay.dom.d.ts +21 -0
  225. package/dist/replay.dom.js +388 -0
  226. package/dist/replay.js +579 -0
  227. package/dist/replay.types.d.ts +152 -0
  228. package/dist/replay.types.js +1 -0
  229. package/dist/restyle.d.ts +21 -0
  230. package/dist/restyle.js +70 -0
  231. package/dist/road.d.ts +26 -0
  232. package/dist/road.draw.d.ts +6 -0
  233. package/dist/road.draw.js +269 -0
  234. package/dist/road.js +59 -0
  235. package/dist/road.model.d.ts +63 -0
  236. package/dist/road.model.js +215 -0
  237. package/dist/road.style.d.ts +7 -0
  238. package/dist/road.style.js +26 -0
  239. package/dist/road.types.d.ts +122 -0
  240. package/dist/road.types.js +1 -0
  241. package/dist/scene-entry.d.ts +7 -0
  242. package/dist/scene-entry.js +5 -0
  243. package/dist/scene.css.d.ts +44 -0
  244. package/dist/scene.css.js +296 -0
  245. package/dist/scene.d.ts +27 -0
  246. package/dist/scene.fit.d.ts +12 -0
  247. package/dist/scene.fit.js +18 -0
  248. package/dist/scene.flat.d.ts +38 -0
  249. package/dist/scene.flat.js +167 -0
  250. package/dist/scene.js +420 -0
  251. package/dist/scene.path.d.ts +40 -0
  252. package/dist/scene.path.js +357 -0
  253. package/dist/scene.types.d.ts +172 -0
  254. package/dist/scene.types.js +1 -0
  255. package/dist/scene.xml.d.ts +31 -0
  256. package/dist/scene.xml.js +81 -0
  257. package/dist/score.d.ts +70 -0
  258. package/dist/score.js +212 -0
  259. package/dist/sets.board.d.ts +22 -0
  260. package/dist/sets.board.js +89 -0
  261. package/dist/sheet.d.ts +18 -0
  262. package/dist/sheet.js +38 -0
  263. package/dist/special.d.ts +44 -0
  264. package/dist/special.js +204 -0
  265. package/dist/special.style.d.ts +8 -0
  266. package/dist/special.style.js +36 -0
  267. package/dist/strings.d.ts +581 -0
  268. package/dist/strings.js +411 -0
  269. package/dist/style.d.ts +35 -0
  270. package/dist/style.js +177 -0
  271. package/dist/surfaces/baseball.d.ts +33 -0
  272. package/dist/surfaces/baseball.js +208 -0
  273. package/dist/surfaces/baseball.walls.d.ts +16 -0
  274. package/dist/surfaces/baseball.walls.js +150 -0
  275. package/dist/surfaces/basketball.d.ts +8 -0
  276. package/dist/surfaces/basketball.js +199 -0
  277. package/dist/surfaces/curling.d.ts +23 -0
  278. package/dist/surfaces/curling.js +128 -0
  279. package/dist/surfaces/field.d.ts +12 -0
  280. package/dist/surfaces/field.js +163 -0
  281. package/dist/surfaces/football.d.ts +12 -0
  282. package/dist/surfaces/football.js +208 -0
  283. package/dist/surfaces/hockey.d.ts +10 -0
  284. package/dist/surfaces/hockey.js +166 -0
  285. package/dist/surfaces/net.d.ts +7 -0
  286. package/dist/surfaces/net.js +151 -0
  287. package/dist/surfaces/soccer-providers.d.ts +124 -0
  288. package/dist/surfaces/soccer-providers.js +334 -0
  289. package/dist/surfaces/soccer-spec.d.ts +138 -0
  290. package/dist/surfaces/soccer-spec.js +175 -0
  291. package/dist/surfaces/soccer.d.ts +25 -0
  292. package/dist/surfaces/soccer.js +270 -0
  293. package/dist/surfaces/surface.d.ts +180 -0
  294. package/dist/surfaces/surface.js +49 -0
  295. package/dist/team.common.d.ts +75 -0
  296. package/dist/team.common.js +97 -0
  297. package/dist/team.formation.d.ts +24 -0
  298. package/dist/team.formation.js +121 -0
  299. package/dist/team.geometry.d.ts +66 -0
  300. package/dist/team.geometry.js +304 -0
  301. package/dist/team.layers.d.ts +16 -0
  302. package/dist/team.layers.js +32 -0
  303. package/dist/team.motion.d.ts +9 -0
  304. package/dist/team.motion.js +325 -0
  305. package/dist/team.network.d.ts +43 -0
  306. package/dist/team.network.js +215 -0
  307. package/dist/team.shape.d.ts +12 -0
  308. package/dist/team.shape.js +217 -0
  309. package/dist/team.types.d.ts +189 -0
  310. package/dist/team.types.js +1 -0
  311. package/dist/text.d.ts +31 -0
  312. package/dist/text.js +88 -0
  313. package/dist/themes.d.ts +14 -0
  314. package/dist/themes.js +24 -0
  315. package/dist/types.d.ts +565 -0
  316. package/dist/types.js +1 -0
  317. package/dist/units.d.ts +45 -0
  318. package/dist/units.js +90 -0
  319. package/dist/version.d.ts +2 -0
  320. package/dist/version.js +2 -0
  321. package/package.json +234 -4
@@ -0,0 +1,47 @@
1
+ import { type KyogijoWords } from "./strings.ts";
2
+ import { type Surface } from "./surfaces/surface.ts";
3
+ import type { ScoreOptions, SurfaceOptions } from "./types.ts";
4
+ /** The margin each surface has when the options give none (the builders' own defaults), in feet. */
5
+ export declare const DEFAULT_MARGIN: Readonly<Record<string, number>>;
6
+ /** What the annotations are drawn against. */
7
+ export interface NoteEnv {
8
+ o: SurfaceOptions | ScoreOptions;
9
+ surface: Surface;
10
+ turned: boolean;
11
+ /** The language's words. */
12
+ words: KyogijoWords;
13
+ /** The teams' names for a label, in a score drawing. */
14
+ teams: {
15
+ home?: string;
16
+ away?: string;
17
+ };
18
+ }
19
+ /** What the annotations made. */
20
+ export interface Notes {
21
+ /** SVG for the surface's group, in its wide frame. */
22
+ svg: string;
23
+ /** Sentences for the description. */
24
+ summaries: string[];
25
+ /** The margin, in feet, that the annotations need all round: the drawing is made at least this wide. */
26
+ need: number;
27
+ }
28
+ /** The surface's wide frame view: the drawing's viewBox as the surface lies wide, which for a turned surface is found again from its turn. */
29
+ export declare function wideView(surface: Surface): {
30
+ x: number;
31
+ y: number;
32
+ w: number;
33
+ h: number;
34
+ };
35
+ type P = readonly [number, number];
36
+ /** Where a direction in the wide frame points on the screen: a quarter turn clockwise sends `(dx, dy)` to `(-dy, dx)`. */
37
+ export declare const onScreen: (turned: boolean, [dx, dy]: P) => P;
38
+ /** A round step that gives about `count` ticks over a span. */
39
+ export declare function niceStep(span: number, count?: number): number;
40
+ /** True when the options ask for any annotation. */
41
+ export declare const annotated: (o: SurfaceOptions | ScoreOptions) => boolean;
42
+ /**
43
+ * The annotations of a drawing: their SVG in the surface's wide frame, a sentence for each for the description, and the margin they need. `need` is
44
+ * measured from the surface's edge, so a caller who finds it larger than the margin the surface has draws the surface again with it.
45
+ */
46
+ export declare function annotate(env: NoteEnv): Notes;
47
+ export {};
@@ -0,0 +1,349 @@
1
+ // Annotations for a surface: the way each team attacks (an arrow in the margin), axes with ticks along its edges (in its own numbers or a provider's frame),
2
+ // and the names of its parts (blue lines, the three-point arc, hog lines...) with a leader to each. They are drawn in the surface's wide frame, inside the
3
+ // group that turns the surface, in the margin the surface leaves round it (which is made wide enough), with the words upright whichever way it lies.
4
+ // The idea of a direction label comes from ggsoccer's `direction_label` and of axes and labels from mplsoccer's pitch `axis` and `label`; the code is our own.
5
+ import { attackingIn, frameByName, toSurface } from "./frames.js";
6
+ import { el, num } from "./format.js";
7
+ import { frameSizeOf } from "./outline.js";
8
+ import { fill } from "./strings.js";
9
+ import { textWidth } from "./text.js";
10
+ import { textOn } from "./surfaces/surface.js";
11
+ import { FEET_PER, SURFACE_UNITS, isUnit } from "./units.js";
12
+ /** The margin each surface has when the options give none (the builders' own defaults), in feet. */
13
+ export const DEFAULT_MARGIN = { nfl: 12, cfl: 12, ifaf: 12, nhl: 8, nba: 7, mlb: 14, soccer: 15, curling: 3, lacrosse: 16, rugby: 16, afl: 16, gaelic: 16, cricket: 9, fieldhockey: 16, handball: 10 };
14
+ const NONE = { svg: "", summaries: [], need: 0, reach: { top: 0, bottom: 0 } };
15
+ /** The surface's wide frame view: the drawing's viewBox as the surface lies wide, which for a turned surface is found again from its turn. */
16
+ export function wideView(surface) {
17
+ if (surface.turn === undefined)
18
+ return surface.view;
19
+ const m = /matrix\(0 1 -1 0 (-?[\d.]+) (-?[\d.]+)\)/.exec(surface.turn);
20
+ if (m === null)
21
+ return surface.view;
22
+ const w = surface.view.h;
23
+ const h = surface.view.w;
24
+ return { x: -Number(m[2]), y: Number(m[1]) - h, w, h };
25
+ }
26
+ /**
27
+ * The font size of the annotations, in feet. A wide drawing is scaled to its longest side, so the size follows that; a tall one is scaled to its narrow side,
28
+ * so it follows that. Either way it is held between what can be read and what would crowd the surface.
29
+ */
30
+ const sizeOf = (box, turned) => (turned ? Math.min(9, Math.max(0.15, 0.045 * Math.min(box.h, box.w))) : Math.min(12, Math.max(0.15, 0.02 * Math.max(box.h, box.w))));
31
+ /** Where a direction in the wide frame points on the screen: a quarter turn clockwise sends `(dx, dy)` to `(-dy, dx)`. */
32
+ export const onScreen = (turned, [dx, dy]) => (turned ? [-dy, dx] : [dx, dy]);
33
+ /** The text anchor that makes a word run away from a point in a direction: along the screen's x it starts or ends there, up or down it is centred. */
34
+ function anchorFor(turned, outward) {
35
+ const [sx, sy] = onScreen(turned, outward);
36
+ if (Math.abs(sx) > Math.abs(sy))
37
+ return sx > 0 ? "start" : "end";
38
+ return "middle";
39
+ }
40
+ /** Text whose cap-height middle line passes through `(x, y)` in the wide frame: the baseline sits 0.36 of the size lower, as `textOn` pivots on the capitals' middle. */
41
+ const word = (g, x, y, text, anchor) => textOn(g.turned, x, y + g.s * 0.36, text, { size: g.s, anchor, cls: "ky-an-t", weight: 600 });
42
+ const stroke = (d, width, cls = "ky-an-l") => el("path", { class: cls, d, "stroke-width": width, fill: "none", "stroke-linecap": "round" });
43
+ // ---- Direction. ----
44
+ /** The sports whose teams attack an end. */
45
+ const ENDS = new Set(["nfl", "cfl", "ifaf", "nhl", "nba", "soccer", "lacrosse", "rugby", "afl", "gaelic", "fieldhockey", "handball"]);
46
+ /** The side a team attacks in the period asked for. */
47
+ function sideIn(sport, d, first) {
48
+ return d.period === undefined ? first : attackingIn(sport, d.period, first, d.changedAfter);
49
+ }
50
+ /** One team's arrow, in the margin below the surface (the home team's) or above it (the away team's), and its label. Returns the markup and the margin it needs. */
51
+ function arrow(g, role, side, label, off) {
52
+ const { s, box } = g;
53
+ const bottom = role === "home";
54
+ const length = Math.min(box.w * 0.35, 12 * s);
55
+ const cx = box.x + box.w / 2;
56
+ const dir = side === "right" ? 1 : -1;
57
+ const out = bottom ? 1 : -1;
58
+ const edge = bottom ? box.y + box.h : box.y;
59
+ const y = edge + out * (off + 1.4 * s);
60
+ const head = 0.9 * s;
61
+ const colour = role === "home" ? "ky-an-h" : "ky-an-a";
62
+ const x1 = cx + (dir * length) / 2;
63
+ let svg = stroke(`M${num(cx - (dir * length) / 2)} ${num(y)}H${num(x1 - dir * head * 0.6)}`, s * 0.28, `ky-an-ar ${colour}`);
64
+ svg += el("path", { class: `ky-an-hd ${colour}`, d: `M${num(x1)} ${num(y)}L${num(x1 - dir * head)} ${num(y - 0.6 * s)}V${num(y + 0.6 * s)}Z` });
65
+ let need = off + 2.4 * s;
66
+ if (label !== undefined) {
67
+ // The label stands beyond the arrow: below or above it on a wide drawing, to the side of it (away from the surface) on a tall one.
68
+ const width = textWidth(label) * s;
69
+ if (g.turned) {
70
+ svg += word(g, cx, edge + out * (off + 2.6 * s), label, anchorFor(true, [0, out]));
71
+ need = off + 2.6 * s + width + 0.5 * s;
72
+ }
73
+ else {
74
+ svg += word(g, cx, edge + out * (off + 3.2 * s), label, "middle");
75
+ need = off + 4.4 * s;
76
+ }
77
+ }
78
+ return { svg, need };
79
+ }
80
+ function directionNotes(env, g, off) {
81
+ const d = env.o.direction;
82
+ if (d === undefined || d === null || typeof d !== "object")
83
+ return NONE;
84
+ if (!ENDS.has(env.o.sport))
85
+ throw new RangeError(`The ${env.o.sport} surface has no ends to attack: direction is for ${[...ENDS].join(", ")}`);
86
+ const words = env.words.notes;
87
+ let svg = "";
88
+ const summaries = [];
89
+ let need = 0;
90
+ const reach = { ...off };
91
+ for (const role of ["home", "away"]) {
92
+ const first = d[role];
93
+ if (first !== "left" && first !== "right")
94
+ continue;
95
+ const side = sideIn(env.o.sport, d, first);
96
+ const team = env.teams[role] ?? (role === "home" ? words.home : words.away);
97
+ const given = typeof d.label === "string" ? d.label : typeof d.label === "object" && d.label !== null ? d.label[role] : undefined;
98
+ const text = d.label === false ? undefined : (given ?? fill(words.attacking, { team }));
99
+ const drawn = arrow(g, role, side, text, role === "home" ? off.bottom : off.top);
100
+ svg += drawn.svg;
101
+ need = Math.max(need, drawn.need);
102
+ reach[role === "home" ? "bottom" : "top"] = drawn.need;
103
+ const sideWord = side === "left" ? words.left : words.right;
104
+ summaries.push(d.period === undefined ? fill(words.attacks, { team, side: sideWord }) : fill(words.attacksIn, { team, side: sideWord, n: d.period }));
105
+ }
106
+ return { svg: svg === "" ? "" : el("g", { class: "ky-an ky-an-dir" }, svg), summaries, need, reach };
107
+ }
108
+ // ---- Axes. ----
109
+ /** A round step that gives about `count` ticks over a span. */
110
+ export function niceStep(span, count = 8) {
111
+ const raw = Math.abs(span) / count;
112
+ if (!(raw > 0) || !Number.isFinite(raw))
113
+ return 1;
114
+ const power = 10 ** Math.floor(Math.log10(raw));
115
+ const unit = raw / power;
116
+ return (unit < 1.5 ? 1 : unit < 3.5 ? 2 : unit < 7.5 ? 5 : 10) * power;
117
+ }
118
+ /** The values in `[lo, hi]` that are multiples of a step, or the list given. */
119
+ function tickValues(given, lo, hi) {
120
+ if (Array.isArray(given))
121
+ return given.filter((v) => typeof v === "number" && Number.isFinite(v));
122
+ const step = typeof given === "number" && given > 0 ? given : niceStep(hi - lo);
123
+ const out = [];
124
+ for (let k = Math.ceil(lo / step - 1e-9); k * step <= hi + 1e-9 && out.length < 400; k += 1)
125
+ out.push(Math.round(k * step * 1e6) / 1e6);
126
+ return out;
127
+ }
128
+ const tickLabel = (v) => String(Math.round(v * 100) / 100);
129
+ /** The two axes of the surface's own numbers (the options' `units`, else the rulebook's), or of a frame of the sport. */
130
+ function axesOf(env, g) {
131
+ const a = env.o.axes;
132
+ const { box } = g;
133
+ const per = (axis) => {
134
+ const ticks = a.ticks;
135
+ if (typeof ticks === "object" && ticks !== null && !Array.isArray(ticks))
136
+ return ticks[axis];
137
+ return ticks;
138
+ };
139
+ if (a.frame === undefined) {
140
+ const unit = env.o.units !== undefined && isUnit(env.o.units) ? env.o.units : (SURFACE_UNITS[env.o.sport] ?? "ft");
141
+ const k = FEET_PER[unit];
142
+ const ranges = [[box.x / k, (box.x + box.w) / k], [box.y / k, (box.y + box.h) / k]];
143
+ return {
144
+ axes: [
145
+ { name: "x", along: "length", ticks: tickValues(per("x"), ranges[0][0], ranges[0][1]).map((value) => ({ value, at: value * k })) },
146
+ { name: "y", along: "width", ticks: tickValues(per("y"), ranges[1][0], ranges[1][1]).map((value) => ({ value, at: value * k })) },
147
+ ],
148
+ ranges,
149
+ unit,
150
+ frame: undefined,
151
+ };
152
+ }
153
+ const frame = typeof a.frame === "string" ? frameByName(a.frame) : a.frame;
154
+ if (frame.sport !== env.o.sport)
155
+ throw new RangeError(`The frame "${frame.name}" is for ${frame.sport}, not ${env.o.sport}`);
156
+ const ranges = [[Math.min(...frame.x), Math.max(...frame.x)], [Math.min(...frame.y), Math.max(...frame.y)]];
157
+ // A frame is fitted to the whole surface, not to the part of it that is shown.
158
+ const size = frameSizeOf(env.o, env.surface.whole ?? box);
159
+ const placed = (point) => toSurface([point], { from: frame, units: "ft", size })[0];
160
+ const mid = [(ranges[0][0] + ranges[0][1]) / 2, (ranges[1][0] + ranges[1][1]) / 2];
161
+ // Which way each axis of the frame runs on the surface: nudge it and see where the point moves.
162
+ const there = placed(mid);
163
+ const nx = placed([mid[0] + 1, mid[1]]);
164
+ const ny = placed([mid[0], mid[1] + 1]);
165
+ const xAlong = Math.abs(nx[0] - there[0]) >= Math.abs(nx[1] - there[1]) ? "length" : "width";
166
+ const yAlong = Math.abs(ny[0] - there[0]) >= Math.abs(ny[1] - there[1]) ? "length" : "width";
167
+ const slack = Math.max(box.w, box.h) * 1e-6;
168
+ const ticksOf = (name, along) => {
169
+ const [lo, hi] = name === "x" ? ranges[0] : ranges[1];
170
+ const edge = along === "length" ? [box.x, box.x + box.w] : [box.y, box.y + box.h];
171
+ const ticks = tickValues(per(name), lo, hi)
172
+ .map((value) => {
173
+ const p = placed(name === "x" ? [value, mid[1]] : [mid[0], value]);
174
+ return { value, at: along === "length" ? p[0] : p[1] };
175
+ })
176
+ .filter((tick) => tick.at >= edge[0] - slack && tick.at <= edge[1] + slack);
177
+ return { name, along, ticks };
178
+ };
179
+ return { axes: [ticksOf("x", xAlong), ticksOf("y", yAlong)], ranges, unit: String(frame.unit), frame: frame.name };
180
+ }
181
+ function axesNotes(env, g) {
182
+ const a = env.o.axes;
183
+ if (a === undefined || a === null || typeof a !== "object")
184
+ return NONE;
185
+ const { s, box, turned } = g;
186
+ const words = env.words.notes;
187
+ const { axes, ranges, unit, frame } = axesOf(env, g);
188
+ const titles = typeof a.labels === "object" && a.labels !== null ? a.labels : {};
189
+ const numbered = a.labels !== false;
190
+ let svg = "";
191
+ let need = 0;
192
+ const reach = { top: 0, bottom: 0 };
193
+ const pad = 0.6 * s;
194
+ const tick = 0.5 * s;
195
+ const base = pad + tick + 0.45 * s;
196
+ for (const axis of axes) {
197
+ if (axis.ticks.length === 0)
198
+ continue;
199
+ const bottom = axis.along === "length";
200
+ // The bottom edge for an axis along the length, the left edge for one along the width.
201
+ const edge = bottom ? box.y + box.h : box.x;
202
+ const n = bottom ? [0, 1] : [-1, 0];
203
+ const at = (t, out) => (bottom ? [t, edge + out] : [edge - out, t]);
204
+ const ts = axis.ticks.map((one) => one.at);
205
+ const lo = Math.min(...ts);
206
+ const hi = Math.max(...ts);
207
+ const p0 = at(lo, pad);
208
+ const p1 = at(hi, pad);
209
+ let d = `M${num(p0[0])} ${num(p0[1])}L${num(p1[0])} ${num(p1[1])}`;
210
+ for (const one of axis.ticks) {
211
+ const a0 = at(one.at, pad);
212
+ const a1 = at(one.at, pad + tick);
213
+ d += `M${num(a0[0])} ${num(a0[1])}L${num(a1[0])} ${num(a1[1])}`;
214
+ }
215
+ svg += stroke(d, s * 0.1);
216
+ // The words stand beside the axis on a screen's side (they run away from it, so they start or end at the tick) or above and below it (centred).
217
+ const anchor = anchorFor(turned, n);
218
+ const across = anchor !== "middle";
219
+ const lift = across ? 0 : 0.6 * s;
220
+ let widest = 0;
221
+ if (numbered) {
222
+ for (const one of axis.ticks) {
223
+ const text = tickLabel(one.value);
224
+ widest = Math.max(widest, textWidth(text) * s);
225
+ const [wx, wy] = at(one.at, base + lift);
226
+ svg += word(g, wx, wy, text, anchor);
227
+ }
228
+ }
229
+ const title = axis.name === "x" ? titles.x : titles.y;
230
+ const hasTitle = typeof title === "string" && title !== "";
231
+ if (hasTitle) {
232
+ const [wx, wy] = at((lo + hi) / 2, base + (across ? widest + 1 * s : 2 * s + lift));
233
+ svg += word(g, wx, wy, title, anchor);
234
+ }
235
+ const titleWidth = hasTitle ? textWidth(title) * s : 0;
236
+ const reachOf = across ? base + (numbered ? widest : 0) + (hasTitle ? 1 * s + titleWidth : 0) + 0.3 * s : base + (hasTitle ? 3.3 * s : numbered ? 1.3 * s : 0.3 * s);
237
+ need = Math.max(need, reachOf);
238
+ if (bottom)
239
+ reach.bottom = reachOf;
240
+ }
241
+ const x0 = tickLabel(ranges[0][0]);
242
+ const x1 = tickLabel(ranges[0][1]);
243
+ const y0 = tickLabel(ranges[1][0]);
244
+ const y1 = tickLabel(ranges[1][1]);
245
+ const summary = frame === undefined ? fill(words.axesSurface, { unit, x0, x1, y0, y1 }) : fill(words.axesFrame, { frame, unit, x0, x1, y0, y1 });
246
+ return { svg: svg === "" ? "" : el("g", { class: "ky-an ky-an-axes" }, svg), summaries: [summary], need, reach };
247
+ }
248
+ // ---- Landmarks. ----
249
+ function landmarkNotes(env, g, off) {
250
+ const marks = env.surface.marks;
251
+ if (env.o.landmarks !== true || marks === undefined)
252
+ return NONE;
253
+ const { s, box, view, turned } = g;
254
+ const names = env.words.notes.names;
255
+ // A part outside what the drawing shows (one end of a half-pitch) is left out.
256
+ // Cropped to a range, the ground the annotations have beyond the cut is not part of what is shown.
257
+ const area = env.surface.cut ?? view;
258
+ const shown = marks.filter((mark) => mark.x >= area.x && mark.x <= area.x + area.w && mark.y >= area.y && mark.y <= area.y + area.h && names[mark.id] !== undefined);
259
+ let svg = "";
260
+ let dots = "";
261
+ let need = 0;
262
+ const reach = { ...off };
263
+ const gap = 1.0 * s;
264
+ const pitch = 1.55 * s;
265
+ const height = 1.25 * s;
266
+ for (const side of ["top", "bottom"]) {
267
+ const out = side === "top" ? -1 : 1;
268
+ const n = [0, out];
269
+ const edge = side === "top" ? box.y : box.y + box.h;
270
+ const start = gap + off[side];
271
+ const list = shown.filter((mark) => mark.side === side).sort((a, b) => a.x - b.x);
272
+ if (list.length === 0)
273
+ continue;
274
+ if (!turned) {
275
+ // A wide drawing: each word stands in the margin above or below its part, in the first row where it clears the others and no leader runs through a word.
276
+ const rows = [];
277
+ let used = 0;
278
+ for (const mark of list) {
279
+ const text = names[mark.id];
280
+ const w = textWidth(text) * s + 0.9 * s;
281
+ const centre = Math.min(Math.max(mark.x, view.x + w / 2), view.x + view.w - w / 2);
282
+ const lo = centre - w / 2;
283
+ const hi = centre + w / 2;
284
+ // The first row where the word clears its neighbours and no leader runs through a word; failing that, the first row where it clears them.
285
+ const fits = (row, keepClear) => (rows[row] ?? (rows[row] = [])).every((iv) => iv.hi <= lo || iv.lo >= hi) && (!keepClear || rows.slice(0, row).every((r) => r.every((iv) => mark.x < iv.lo - 0.3 * s || mark.x > iv.hi + 0.3 * s)));
286
+ const row = [0, 1, 2, 3, 4].find((r) => fits(r, true)) ?? [0, 1, 2, 3, 4].find((r) => fits(r, false)) ?? 4;
287
+ (rows[row] ?? (rows[row] = [])).push({ lo, hi });
288
+ used = Math.max(used, row + 1);
289
+ const near = edge + out * (start + row * pitch);
290
+ svg += stroke(`M${num(mark.x)} ${num(mark.y)}L${num(centre)} ${num(near)}`, s * 0.1);
291
+ svg += word(g, centre, near + out * (height / 2), text, "middle");
292
+ dots += el("circle", { cx: mark.x, cy: mark.y, r: s * 0.3, "stroke-width": s * 0.12 });
293
+ }
294
+ reach[side] = start + height + (used - 1) * pitch + 0.2 * s;
295
+ need = Math.max(need, reach[side]);
296
+ }
297
+ else {
298
+ // A tall drawing: each word runs out sideways from the margin's edge, one under another, pushed apart where their parts are close.
299
+ const slot = 1.4 * s;
300
+ const at = list.map((mark) => mark.x);
301
+ for (let i = 1; i < at.length; i += 1)
302
+ at[i] = Math.max(at[i], at[i - 1] + slot);
303
+ at[at.length - 1] = Math.min(at[at.length - 1], view.x + view.w - 0.7 * s);
304
+ for (let i = at.length - 2; i >= 0; i -= 1)
305
+ at[i] = Math.min(at[i], at[i + 1] - slot);
306
+ for (let i = 0; i < at.length; i += 1)
307
+ at[i] = Math.max(at[i], view.x + 0.7 * s);
308
+ const anchor = anchorFor(true, n);
309
+ list.forEach((mark, i) => {
310
+ const text = names[mark.id];
311
+ const near = edge + out * start;
312
+ svg += stroke(`M${num(mark.x)} ${num(mark.y)}L${num(at[i])} ${num(near)}`, s * 0.1);
313
+ svg += word(g, at[i], near + out * 0.3 * s, text, anchor);
314
+ dots += el("circle", { cx: mark.x, cy: mark.y, r: s * 0.3, "stroke-width": s * 0.12 });
315
+ reach[side] = Math.max(reach[side], start + 0.3 * s + textWidth(text) * s + 0.5 * s);
316
+ need = Math.max(need, reach[side]);
317
+ });
318
+ }
319
+ }
320
+ const unique = [...new Set(shown.map((mark) => names[mark.id]))];
321
+ return {
322
+ svg: svg === "" ? "" : el("g", { class: "ky-an ky-an-marks" }, `${svg}${el("g", { class: "ky-an-d" }, dots)}`),
323
+ summaries: unique.length === 0 ? [] : [fill(env.words.notes.labelled, { list: unique.join(env.words.layers.listSep) })],
324
+ need,
325
+ reach,
326
+ };
327
+ }
328
+ /** True when the options ask for any annotation. */
329
+ export const annotated = (o) => o.direction !== undefined || o.axes !== undefined || o.landmarks === true;
330
+ /**
331
+ * The annotations of a drawing: their SVG in the surface's wide frame, a sentence for each for the description, and the margin they need. `need` is
332
+ * measured from the surface's edge, so a caller who finds it larger than the margin the surface has draws the surface again with it.
333
+ */
334
+ export function annotate(env) {
335
+ const box = env.surface.box;
336
+ if (box === undefined || !annotated(env.o))
337
+ return NONE;
338
+ const g = { s: sizeOf(box, env.turned), box, view: wideView(env.surface), turned: env.turned };
339
+ // From the surface outwards: the axes, then the labels of its parts, then the arrows.
340
+ const axes = axesNotes(env, g);
341
+ const marks = landmarkNotes(env, g, axes.reach);
342
+ const direction = directionNotes(env, g, marks.reach);
343
+ const parts = [direction, axes, marks];
344
+ return {
345
+ svg: parts.map((part) => part.svg).join(""),
346
+ summaries: parts.flatMap((part) => part.summaries),
347
+ need: Math.max(...parts.map((part) => part.need)),
348
+ };
349
+ }
@@ -0,0 +1,4 @@
1
+ export { PLACES, atlasFacets, placeById, placeByName, placesBy, placesByName, surfaceOf } from "./atlas.ts";
2
+ export { officialName, plainName } from "./names.ts";
3
+ export type { PlaceAlias, PlaceNameKind } from "./names.ts";
4
+ export type { AtlasFacets, Place, PlaceFilter, PlaceKind, PlaceSport, PlaceStatus } from "./atlas.ts";
@@ -0,0 +1,3 @@
1
+ // The atlas: every ballpark and soccer ground with where it stands and when it was in use, and the filters over them.
2
+ export { PLACES, atlasFacets, placeById, placeByName, placesBy, placesByName, surfaceOf } from "./atlas.js";
3
+ export { officialName, plainName } from "./names.js";
@@ -0,0 +1,131 @@
1
+ import type { PlaceAlias } from "./names.ts";
2
+ /** What a place is: a ballpark (of `PARKS`) or a soccer ground (of `GROUNDS`). */
3
+ export type PlaceKind = "park" | "ground";
4
+ /** The sport a place is drawn for: baseball parks have a fence, soccer grounds a pitch. */
5
+ export type PlaceSport = "baseball" | "soccer";
6
+ /** `current` is a ground a club or a competition uses today, `past` one it has left, closed or pulled down. */
7
+ export type PlaceStatus = "current" | "past";
8
+ /** One place on the atlas: a ballpark or a soccer ground, with where it is and when it was in use. */
9
+ export interface Place {
10
+ /** The key in `PARKS` or in `GROUNDS` (`fenway-park`, `maracana`): unique across both. */
11
+ id: string;
12
+ kind: PlaceKind;
13
+ /** The everyday name in English. */
14
+ name: string;
15
+ /** The everyday name in Japanese. */
16
+ nameJa: string;
17
+ /** The reading of `nameJa` in kana, where it has kanji. */
18
+ readingJa?: string;
19
+ /** The everyday name in the language of the place, where it is not English. */
20
+ localName?: string;
21
+ localLanguage?: string;
22
+ /** Every other name: the cited titles of Wikipedia, the official, sponsor and former names with their years, the nicknames; `placeByName` and the `text` of `placesBy` read them. */
23
+ aliases: readonly PlaceAlias[];
24
+ /** The names the place had for some years (a ground that was given another name for a World Cup), first to last. */
25
+ names?: readonly {
26
+ name: string;
27
+ from: number;
28
+ to: number;
29
+ }[];
30
+ sport: PlaceSport;
31
+ /** The leagues and competitions it is known for: `MLB`, `NPB`, `FIFA World Cup`, `FIFA Women's World Cup`. A club ground that staged none has none. */
32
+ leagues: readonly string[];
33
+ /** ISO 3166-1 alpha-2: `US`. */
34
+ country: string;
35
+ city: string;
36
+ /** The club that plays in a park (`Boston Red Sox`); soccer grounds have none. */
37
+ team?: string;
38
+ /** Wikidata's coordinates (P625, CC0), in degrees. */
39
+ lat: number;
40
+ lon: number;
41
+ status: PlaceStatus;
42
+ /** The first year it was in use: a past MLB park's first MLB season, else the year it opened. Not given where Wikidata and the article do not give it. */
43
+ from?: number;
44
+ /** The last year it was in use: a past MLB park's last MLB season, else the year it closed. A current place has none. */
45
+ to?: number;
46
+ /** The Wikidata item (`Q49136`): the key to join a place to other data. */
47
+ wikidata: string;
48
+ }
49
+ /** What `placesBy` keeps: every field given must match. A list matches any of its members. */
50
+ export interface PlaceFilter {
51
+ sport?: PlaceSport | readonly PlaceSport[];
52
+ kind?: PlaceKind | readonly PlaceKind[];
53
+ /** A league or competition from `Place.leagues`. */
54
+ league?: string | readonly string[];
55
+ /** ISO 3166-1 alpha-2. */
56
+ country?: string | readonly string[];
57
+ status?: PlaceStatus | readonly PlaceStatus[];
58
+ /** Keep the places in use in this year. A year that is not known for a place (no `from`, no `to`) does not shut it out. */
59
+ year?: number;
60
+ /** Words to find in any name (the everyday names, the aliases, the readings), the city or the club, ignoring case, accents, width and, in Japanese, hiragana or katakana; every word must be found. */
61
+ text?: string;
62
+ }
63
+ /**
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.
66
+ * @example
67
+ * ```ts
68
+ * import { PLACES } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
69
+ * const fenway = PLACES.find((place) => place.id === "fenway-park");
70
+ * console.log(fenway?.name, fenway?.lat, fenway?.lon, fenway?.country);
71
+ * // Fenway Park 42.34639 -71.0975 US
72
+ * ```
73
+ */
74
+ export declare const PLACES: readonly Place[];
75
+ /** The place with a key, or `undefined`. */
76
+ export declare const placeById: (id: string | undefined) => Place | undefined;
77
+ /**
78
+ * The places that answer to a name, best match first: the everyday names, then the official and cited names and the sponsors', then the former names and the nicknames. The comparison
79
+ * ignores case, accents, spaces and punctuation, width, and in Japanese hiragana or katakana and the long vowel mark.
80
+ * @example
81
+ * ```ts
82
+ * import { placeByName, placesByName } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
83
+ * console.log(placeByName("Koshien Stadium")?.id, placeByName("サン・シーロ")?.id, placeByName("Estadio Jornalista Mario Filho")?.id, placesByName("wrigley field").map((place) => place.id).join());
84
+ * // hanshin-koshien-stadium san-siro maracana wrigley-field,wrigley-field-los-angeles
85
+ * ```
86
+ */
87
+ export declare const placesByName: (name: string | undefined) => Place[];
88
+ /** The place a name belongs to (see `placesByName`; the best match when several answer to it), or `undefined`. */
89
+ export declare const placeByName: (name: string | undefined) => Place | undefined;
90
+ /**
91
+ * The places that match every field of the filter, in the order of `PLACES`.
92
+ * @example
93
+ * ```ts
94
+ * import { placesBy } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
95
+ * const japan = placesBy({ sport: "baseball", country: "JP", status: "current" });
96
+ * const in1950 = placesBy({ year: 1950, country: "US" });
97
+ * console.log(japan.length, in1950.some((place) => place.id === "ebbets-field"));
98
+ * // 14 true
99
+ * ```
100
+ */
101
+ export declare function placesBy(filter?: PlaceFilter): Place[];
102
+ /** What the places hold, for the controls of a page: each list sorted, the years as far as the data gives them. */
103
+ export interface AtlasFacets {
104
+ sports: PlaceSport[];
105
+ leagues: string[];
106
+ countries: string[];
107
+ /** The first and the last year any place gives (`from` or `to`). */
108
+ years: {
109
+ min: number;
110
+ max: number;
111
+ };
112
+ }
113
+ /**
114
+ * The sports, leagues and countries of the places, and the span of years they give.
115
+ * @example
116
+ * ```ts
117
+ * import { atlasFacets } from "@johnmorrisdotca/kyogijo-stadiums/atlas";
118
+ * const { sports, leagues, countries, years } = atlasFacets();
119
+ * console.log(sports.join(), leagues.join(), countries.length, years.min);
120
+ * // baseball,soccer FIFA Women's World Cup,FIFA World Cup,MLB,NPB 23 1877
121
+ * ```
122
+ */
123
+ export declare function atlasFacets(): AtlasFacets;
124
+ /** The options `drawKyogijo` takes to draw a place's surface: a park's fence or a ground's pitch at its own size. */
125
+ export declare function surfaceOf(place: Place): {
126
+ sport: "mlb";
127
+ park: string;
128
+ } | {
129
+ sport: "soccer";
130
+ ground: string;
131
+ };