@johnmorrisdotca/kyogijo-stadiums 0.4.0 → 0.6.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 +133 -0
- package/NOTICE.md +182 -2
- package/README.md +106 -19
- package/dist/annotate.js +1 -1
- package/dist/arenas-entry.d.ts +4 -0
- package/dist/arenas-entry.js +3 -0
- package/dist/arenas.d.ts +125 -0
- package/dist/arenas.data.d.ts +2 -0
- package/dist/arenas.data.js +3763 -0
- package/dist/arenas.js +72 -0
- package/dist/athletics/describe.d.ts +8 -0
- package/dist/athletics/describe.js +41 -0
- package/dist/athletics/events.d.ts +17 -0
- package/dist/athletics/events.js +48 -0
- package/dist/athletics/facilities.d.ts +80 -0
- package/dist/athletics/facilities.js +176 -0
- package/dist/athletics/infield.d.ts +79 -0
- package/dist/athletics/infield.js +166 -0
- package/dist/athletics/layout.d.ts +13 -0
- package/dist/athletics/layout.js +98 -0
- package/dist/athletics/oval.d.ts +57 -0
- package/dist/athletics/oval.js +116 -0
- package/dist/athletics/plan.d.ts +97 -0
- package/dist/athletics/plan.js +355 -0
- package/dist/athletics/races.d.ts +102 -0
- package/dist/athletics/races.js +355 -0
- package/dist/athletics/steeplechase.d.ts +72 -0
- package/dist/athletics/steeplechase.js +196 -0
- package/dist/athletics/stencil.d.ts +13 -0
- package/dist/athletics/stencil.js +85 -0
- package/dist/athletics/track.d.ts +54 -0
- package/dist/athletics/track.js +105 -0
- package/dist/athletics/types.d.ts +77 -0
- package/dist/athletics/types.js +1 -0
- package/dist/athletics-entry.d.ts +17 -0
- package/dist/athletics-entry.js +11 -0
- package/dist/athletics.style.d.ts +16 -0
- package/dist/athletics.style.js +51 -0
- package/dist/atlas-entry.d.ts +6 -2
- package/dist/atlas-entry.js +4 -2
- package/dist/atlas.d.ts +117 -23
- package/dist/atlas.js +197 -12
- package/dist/background.js +2 -1
- package/dist/budo/describe.d.ts +13 -0
- package/dist/budo/describe.js +120 -0
- package/dist/budo/dojo.api.d.ts +64 -0
- package/dist/budo/dojo.api.js +46 -0
- package/dist/budo/dojo.d.ts +72 -0
- package/dist/budo/dojo.js +300 -0
- package/dist/budo/judo.d.ts +61 -0
- package/dist/budo/judo.js +109 -0
- package/dist/budo/karate.d.ts +29 -0
- package/dist/budo/karate.js +80 -0
- package/dist/budo/kendo.d.ts +18 -0
- package/dist/budo/kendo.js +44 -0
- package/dist/budo/kimarite.d.ts +19 -0
- package/dist/budo/kimarite.js +33 -0
- package/dist/budo/kit.d.ts +16 -0
- package/dist/budo/kit.js +24 -0
- package/dist/budo/kyudo.d.ts +28 -0
- package/dist/budo/kyudo.js +66 -0
- package/dist/budo/looks.d.ts +28 -0
- package/dist/budo/looks.js +58 -0
- package/dist/budo/parts.d.ts +32 -0
- package/dist/budo/parts.js +10 -0
- package/dist/budo/plan.d.ts +64 -0
- package/dist/budo/plan.js +139 -0
- package/dist/budo/room.d.ts +133 -0
- package/dist/budo/room.js +111 -0
- package/dist/budo/sumo.d.ts +31 -0
- package/dist/budo/sumo.js +71 -0
- package/dist/budo/tatami.d.ts +55 -0
- package/dist/budo/tatami.js +156 -0
- package/dist/budo/types.d.ts +192 -0
- package/dist/budo/types.js +2 -0
- package/dist/budo-entry.d.ts +22 -0
- package/dist/budo-entry.js +13 -0
- package/dist/budo.board.d.ts +28 -0
- package/dist/budo.board.js +81 -0
- package/dist/budo.score.d.ts +18 -0
- package/dist/budo.score.js +52 -0
- package/dist/budo.style.d.ts +6 -0
- package/dist/budo.style.js +67 -0
- package/dist/charts-entry.d.ts +6 -1
- package/dist/charts-entry.js +3 -0
- package/dist/charts.athletics.d.ts +183 -0
- package/dist/charts.athletics.js +455 -0
- package/dist/charts.baseball.js +1 -1
- package/dist/charts.curling.heat.d.ts +24 -0
- package/dist/charts.curling.heat.js +116 -0
- package/dist/charts.curling.js +14 -3
- package/dist/charts.js +4 -4
- package/dist/charts.pool.d.ts +67 -0
- package/dist/charts.pool.js +76 -0
- package/dist/charts.skating.d.ts +204 -0
- package/dist/charts.skating.js +426 -0
- package/dist/charts.soccer.js +3 -3
- package/dist/charts.types.d.ts +63 -1
- package/dist/colour.d.ts +4 -4
- package/dist/colour.js +4 -4
- package/dist/court.d.ts +85 -2
- package/dist/court.js +102 -7
- package/dist/court.more.d.ts +46 -0
- package/dist/court.more.js +219 -0
- package/dist/courts.style.d.ts +14 -2
- package/dist/courts.style.js +51 -4
- package/dist/crowd.d.ts +164 -0
- package/dist/crowd.draw.d.ts +17 -0
- package/dist/crowd.draw.js +204 -0
- package/dist/crowd.js +480 -0
- package/dist/crowd.park.d.ts +19 -0
- package/dist/crowd.park.js +153 -0
- package/dist/curling.stats.d.ts +271 -0
- package/dist/curling.stats.js +301 -0
- package/dist/draw.d.ts +16 -0
- package/dist/draw.js +462 -54
- package/dist/element-entry.d.ts +3 -1
- package/dist/element-entry.js +2 -1
- package/dist/element.d.ts +13 -2
- package/dist/element.js +79 -4
- package/dist/emblems-source.d.ts +50 -0
- package/dist/emblems-source.js +56 -0
- package/dist/eras.d.ts +3 -1
- package/dist/eras.js +8 -3
- package/dist/features.js +204 -0
- package/dist/field.data.d.ts +16 -0
- package/dist/field.data.js +50 -0
- package/dist/fields.kit.d.ts +2 -2
- package/dist/fields.types.d.ts +24 -4
- package/dist/formations.js +18 -7
- package/dist/formations.sports.d.ts +8 -0
- package/dist/formations.sports.js +251 -0
- package/dist/frames.providers.js +71 -8
- package/dist/geojson.js +3 -0
- package/dist/geometry-entry.d.ts +2 -1
- package/dist/geometry-entry.js +2 -1
- package/dist/geometry.d.ts +20 -0
- package/dist/geometry.js +78 -1
- package/dist/grounds.d.ts +4 -0
- package/dist/grounds.data.js +12 -0
- package/dist/halls.d.ts +65 -0
- package/dist/halls.js +122 -0
- package/dist/hardwood.d.ts +31 -0
- package/dist/hardwood.js +157 -0
- package/dist/heat.js +21 -13
- package/dist/heat.types.d.ts +5 -0
- package/dist/heat.zones.d.ts +4 -2
- package/dist/heat.zones.js +207 -7
- package/dist/homeside.js +24 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +18 -2
- package/dist/layers-entry.d.ts +2 -1
- package/dist/layers-entry.js +1 -0
- package/dist/layers.d.ts +2 -1
- package/dist/layers.env.d.ts +12 -1
- package/dist/layers.env.js +36 -4
- package/dist/layers.js +32 -13
- package/dist/layers.types.d.ts +9 -2
- package/dist/leagues/athletics.d.ts +63 -0
- package/dist/leagues/athletics.js +87 -0
- package/dist/leagues/budo.d.ts +196 -0
- package/dist/leagues/budo.js +105 -0
- package/dist/leagues/courts.d.ts +269 -4
- package/dist/leagues/courts.js +155 -1
- package/dist/leagues/hockey.js +41 -19
- package/dist/leagues/skating.d.ts +145 -0
- package/dist/leagues/skating.js +73 -0
- package/dist/leagues/sources.js +41 -0
- package/dist/leagues/types.d.ts +1 -1
- package/dist/leagues-entry.d.ts +4 -2
- package/dist/leagues-entry.js +2 -1
- package/dist/leagues.d.ts +17 -4
- package/dist/leagues.js +246 -5
- package/dist/lineup.codes.d.ts +23 -0
- package/dist/lineup.codes.js +122 -0
- package/dist/logo.d.ts +25 -0
- package/dist/logo.js +47 -0
- package/dist/look.d.ts +3 -3
- package/dist/look.js +39 -6
- package/dist/outline.d.ts +1 -1
- package/dist/outline.js +46 -4
- package/dist/pageant.d.ts +120 -0
- package/dist/pageant.draw.d.ts +21 -0
- package/dist/pageant.draw.js +171 -0
- package/dist/pageant.js +211 -0
- package/dist/pageant.style.d.ts +8 -0
- package/dist/pageant.style.js +42 -0
- package/dist/png.d.ts +8 -1
- package/dist/png.js +21 -1
- package/dist/pointer-entry.d.ts +2 -0
- package/dist/pointer-entry.js +2 -0
- package/dist/pointer.d.ts +113 -0
- package/dist/pointer.js +151 -0
- package/dist/pool.d.ts +176 -0
- package/dist/pool.figures.d.ts +306 -0
- package/dist/pool.figures.js +148 -0
- package/dist/pool.js +304 -0
- package/dist/pool.kit.d.ts +48 -0
- package/dist/pool.kit.js +141 -0
- package/dist/pool.labels.d.ts +20 -0
- package/dist/pool.labels.js +258 -0
- package/dist/pool.race.d.ts +65 -0
- package/dist/pool.race.js +140 -0
- package/dist/pool.replay.d.ts +46 -0
- package/dist/pool.replay.js +127 -0
- package/dist/pool.section.d.ts +13 -0
- package/dist/pool.section.js +83 -0
- package/dist/pool.style.d.ts +20 -0
- package/dist/pool.style.js +169 -0
- package/dist/pool.types.d.ts +145 -0
- package/dist/pool.types.js +3 -0
- package/dist/pool.words.d.ts +13 -0
- package/dist/pool.words.js +101 -0
- package/dist/ranges.names.js +53 -3
- package/dist/replay-entry.d.ts +3 -0
- package/dist/replay-entry.js +2 -0
- package/dist/restyle.js +1 -1
- package/dist/road.draw.js +3 -2
- package/dist/road.js +2 -1
- package/dist/road.types.d.ts +3 -0
- package/dist/rules.d.ts +138 -0
- package/dist/rules.js +511 -0
- package/dist/rules.types.d.ts +4 -0
- package/dist/rules.types.js +64 -0
- package/dist/score.d.ts +3 -0
- package/dist/score.js +93 -6
- package/dist/sheet.d.ts +3 -0
- package/dist/sheet.js +7 -3
- package/dist/situation.d.ts +135 -0
- package/dist/situation.draw.d.ts +34 -0
- package/dist/situation.draw.js +202 -0
- package/dist/situation.js +337 -0
- package/dist/situation.style.d.ts +2 -0
- package/dist/situation.style.js +45 -0
- package/dist/situation.types.d.ts +77 -0
- package/dist/situation.types.js +3 -0
- package/dist/situation.widgets.d.ts +39 -0
- package/dist/situation.widgets.js +129 -0
- package/dist/skating/describe.d.ts +7 -0
- package/dist/skating/describe.js +44 -0
- package/dist/skating/events.d.ts +24 -0
- package/dist/skating/events.js +47 -0
- package/dist/skating/figure.d.ts +24 -0
- package/dist/skating/figure.js +37 -0
- package/dist/skating/long.d.ts +54 -0
- package/dist/skating/long.js +111 -0
- package/dist/skating/parts.d.ts +43 -0
- package/dist/skating/parts.js +40 -0
- package/dist/skating/plan.d.ts +55 -0
- package/dist/skating/plan.js +197 -0
- package/dist/skating/short.d.ts +47 -0
- package/dist/skating/short.js +89 -0
- package/dist/skating/track.d.ts +66 -0
- package/dist/skating/track.js +94 -0
- package/dist/skating/types.d.ts +57 -0
- package/dist/skating/types.js +3 -0
- package/dist/skating-entry.d.ts +17 -0
- package/dist/skating-entry.js +11 -0
- package/dist/skating.style.d.ts +4 -0
- package/dist/skating.style.js +24 -0
- package/dist/strings.d.ts +470 -0
- package/dist/strings.js +674 -13
- package/dist/style.d.ts +2 -0
- package/dist/style.js +19 -2
- package/dist/surfaces/artistic.d.ts +9 -0
- package/dist/surfaces/artistic.js +94 -0
- package/dist/surfaces/athletics.d.ts +16 -0
- package/dist/surfaces/athletics.js +132 -0
- package/dist/surfaces/baseball.js +17 -0
- package/dist/surfaces/basketball.floor.d.ts +27 -0
- package/dist/surfaces/basketball.floor.js +83 -0
- package/dist/surfaces/basketball.gear.d.ts +27 -0
- package/dist/surfaces/basketball.gear.js +90 -0
- package/dist/surfaces/basketball.js +44 -22
- package/dist/surfaces/budo.d.ts +6 -0
- package/dist/surfaces/budo.js +104 -0
- package/dist/surfaces/curling.d.ts +16 -0
- package/dist/surfaces/curling.fold.d.ts +67 -0
- package/dist/surfaces/curling.fold.js +107 -0
- package/dist/surfaces/curling.js +37 -3
- package/dist/surfaces/dive.d.ts +9 -0
- package/dist/surfaces/dive.js +128 -0
- package/dist/surfaces/field.d.ts +7 -2
- package/dist/surfaces/field.js +15 -9
- package/dist/surfaces/football.js +7 -0
- package/dist/surfaces/hockey.js +4 -2
- package/dist/surfaces/net.d.ts +2 -1
- package/dist/surfaces/net.js +160 -15
- package/dist/surfaces/polo.d.ts +12 -0
- package/dist/surfaces/polo.js +159 -0
- package/dist/surfaces/pool.d.ts +27 -0
- package/dist/surfaces/pool.js +198 -0
- package/dist/surfaces/skating.d.ts +6 -0
- package/dist/surfaces/skating.js +62 -0
- package/dist/surfaces/soccer.js +2 -1
- package/dist/surfaces/surface.d.ts +76 -0
- package/dist/surfaces/venue.d.ts +15 -0
- package/dist/surfaces/venue.js +95 -0
- package/dist/target-entry.d.ts +2 -0
- package/dist/target-entry.js +2 -0
- package/dist/target.d.ts +200 -0
- package/dist/target.js +525 -0
- package/dist/team.common.d.ts +1 -1
- package/dist/team.common.js +3 -3
- package/dist/team.formation.d.ts +3 -1
- package/dist/team.formation.js +3 -3
- package/dist/team.layers.d.ts +2 -2
- package/dist/team.layers.js +4 -1
- package/dist/team.lineup.d.ts +27 -0
- package/dist/team.lineup.js +207 -0
- package/dist/team.network.js +6 -5
- package/dist/team.shape.js +5 -5
- package/dist/team.types.d.ts +40 -1
- package/dist/tenants.d.ts +77 -0
- package/dist/tenants.data.d.ts +8 -0
- package/dist/tenants.data.js +1793 -0
- package/dist/tenants.js +46 -0
- package/dist/turn-entry.d.ts +12 -0
- package/dist/turn-entry.js +7 -0
- package/dist/turn.camera.d.ts +116 -0
- package/dist/turn.camera.js +184 -0
- package/dist/turn.dom.d.ts +40 -0
- package/dist/turn.dom.js +353 -0
- package/dist/turn.kit.d.ts +86 -0
- package/dist/turn.kit.js +110 -0
- package/dist/turn.markup.d.ts +48 -0
- package/dist/turn.markup.js +108 -0
- package/dist/turn.model.d.ts +78 -0
- package/dist/turn.model.js +91 -0
- package/dist/turn.style.d.ts +5 -0
- package/dist/turn.style.js +56 -0
- package/dist/types.d.ts +221 -20
- package/dist/units.d.ts +1 -1
- package/dist/units.js +22 -1
- package/dist/uprights.board.d.ts +17 -0
- package/dist/uprights.board.js +59 -0
- package/dist/uprights.budo.d.ts +17 -0
- package/dist/uprights.budo.js +87 -0
- package/dist/uprights.d.ts +37 -0
- package/dist/uprights.fields.d.ts +32 -0
- package/dist/uprights.fields.js +172 -0
- package/dist/uprights.goal.d.ts +49 -0
- package/dist/uprights.goal.js +69 -0
- package/dist/uprights.js +169 -0
- package/dist/uprights.more.d.ts +7 -0
- package/dist/uprights.more.js +183 -0
- package/dist/uprights.net.d.ts +12 -0
- package/dist/uprights.net.js +109 -0
- package/dist/uprights.netkit.d.ts +28 -0
- package/dist/uprights.netkit.js +67 -0
- package/dist/uprights.pools.d.ts +8 -0
- package/dist/uprights.pools.js +190 -0
- package/dist/uprights.rinks.d.ts +27 -0
- package/dist/uprights.rinks.js +106 -0
- package/dist/uprights.track.d.ts +50 -0
- package/dist/uprights.track.js +246 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/zones-entry.d.ts +2 -0
- package/dist/zones-entry.js +2 -0
- package/package.json +56 -3
package/dist/draw.js
CHANGED
|
@@ -1,22 +1,52 @@
|
|
|
1
1
|
import { ballparkDrawn, ballparkFor, ballparkSentences } from "./ballpark.js";
|
|
2
|
-
import { inkOn, safeColour
|
|
2
|
+
import { inkOn, safeColour } from "./colour.js";
|
|
3
|
+
import { withEmblems } from "./emblems-source.js";
|
|
4
|
+
import { safeLogo } from "./logo.js";
|
|
3
5
|
import { drawingId, feetFence, isPortrait, lengthUnit, safeClass } from "./common.js";
|
|
4
6
|
import { el, esc, num } from "./format.js";
|
|
7
|
+
import { fieldAttributes } from "./field.data.js";
|
|
5
8
|
import { ERA_SPORTS, footballIn, rulesFor, seasonLabel } from "./eras.js";
|
|
6
9
|
import { FOOTBALL } from "./geometry.js";
|
|
7
10
|
import { renderLayers } from "./layers.js";
|
|
11
|
+
import { arenaById, arenaCourtIn, arenaNameIn, arenaOfficialName, arenaRinkIn } from "./arenas.js";
|
|
8
12
|
import { groundById, groundNameIn, groundOfficialName } from "./grounds.js";
|
|
9
|
-
import { courtFor, isNetSport } from "./court.js";
|
|
13
|
+
import { BOARD, courtFor, hasSetsBoard, isNetLeague, isNetSport } from "./court.js";
|
|
10
14
|
import { cricketBoardMarkup } from "./cricket.board.js";
|
|
15
|
+
import { athleticsPlan } from "./athletics/plan.js";
|
|
16
|
+
import { skatingPlan } from "./skating/plan.js";
|
|
17
|
+
import { skatingAbout, skatingSentences } from "./skating/describe.js";
|
|
18
|
+
import { skatingStyle } from "./skating.style.js";
|
|
19
|
+
import { budoPlan, isBudoSport } from "./budo/plan.js";
|
|
20
|
+
import { dojoSpecOf } from "./budo/dojo.js";
|
|
21
|
+
import { dojoGallery } from "./budo/room.js";
|
|
22
|
+
import { budoAbout, budoScoreSentences, budoSentences } from "./budo/describe.js";
|
|
23
|
+
import { lookOf as budoLookOf } from "./budo/looks.js";
|
|
24
|
+
import { kimariteName } from "./budo/kimarite.js";
|
|
25
|
+
import { budoScoreText, budoView } from "./budo.score.js";
|
|
26
|
+
import { KYOGIJO_BUDO_GALLERY_STYLE, budoStyle } from "./budo.style.js";
|
|
27
|
+
import { budoBoardMarkup } from "./budo.board.js";
|
|
28
|
+
import { budoSurface } from "./surfaces/budo.js";
|
|
29
|
+
import { skatingSurface } from "./surfaces/skating.js";
|
|
30
|
+
import { athleticsAbout, athleticsSentences } from "./athletics/describe.js";
|
|
31
|
+
import { athleticsStyle, athleticsTrackRules } from "./athletics.style.js";
|
|
32
|
+
import { athleticsSurface, pitchGroup } from "./surfaces/athletics.js";
|
|
11
33
|
import { fieldPlan, isFieldSport } from "./fields.js";
|
|
12
34
|
import { fieldScoreText, fieldTotal } from "./field.score.js";
|
|
13
35
|
import { fieldsStyle } from "./fields.style.js";
|
|
14
36
|
import { resolveHomeSide } from "./homeside.js";
|
|
15
37
|
import { LEAGUES, chooseLeague, courtOf, diamondOf, fieldOf, hasHistory, leagueSeason, leagueSize, netOf, rinkOf, sheetOf } from "./leagues.js";
|
|
16
|
-
import { diamondFence } from "./leagues/baseball.js";
|
|
17
|
-
import { fenceFor, parkById, parkNameIn, parkOfficialName } from "./parks.js";
|
|
38
|
+
import { MLB_DIAMOND, diamondFence } from "./leagues/baseball.js";
|
|
39
|
+
import { fenceFor, parkById, parkNameIn, parkOfficialName, parkWallsIn } from "./parks.js";
|
|
18
40
|
import { boardMarkup, endText } from "./curling.board.js";
|
|
19
41
|
import { sheetFor } from "./sheet.js";
|
|
42
|
+
import { commonOf, isPoolSport, swimPlan, poloPlan, divePlan, artisticPlan } from "./pool.js";
|
|
43
|
+
import { natatorium } from "./surfaces/venue.js";
|
|
44
|
+
import { poolDescription } from "./pool.words.js";
|
|
45
|
+
import { KYOGIJO_POOL_STYLE, poolStyle } from "./pool.style.js";
|
|
46
|
+
import { swimming } from "./surfaces/pool.js";
|
|
47
|
+
import { waterPolo } from "./surfaces/polo.js";
|
|
48
|
+
import { diving } from "./surfaces/dive.js";
|
|
49
|
+
import { artistic } from "./surfaces/artistic.js";
|
|
20
50
|
import { cropToRange, describeRange, rangeLabel, shows } from "./ranges.js";
|
|
21
51
|
import { badgeMarkup, bannerMarkup, plateMarkup, stateOf } from "./score.js";
|
|
22
52
|
import { setsBoardMarkup } from "./sets.board.js";
|
|
@@ -24,19 +54,32 @@ import { KYOGIJO_STRINGS, fill } from "./strings.js";
|
|
|
24
54
|
import { courtStyle } from "./courts.style.js";
|
|
25
55
|
import { annotate, annotated, wideView } from "./annotate.js";
|
|
26
56
|
import { KYOGIJO_BACKGROUND_STYLE, laidOn } from "./background.js";
|
|
57
|
+
import { KYOGIJO_HARDWOOD_STYLE, resolveHardwood } from "./hardwood.js";
|
|
58
|
+
import { WALL_SEATS, densityOf, layoutOf as crowdLayout, resolveCrowd } from "./crowd.js";
|
|
59
|
+
import { drawCrowd, KYOGIJO_CROWD_STYLE } from "./crowd.draw.js";
|
|
60
|
+
import { parkLayout } from "./crowd.park.js";
|
|
27
61
|
import { featureColours, featureStyle } from "./features.js";
|
|
28
62
|
import { isLook, lookStyle } from "./look.js";
|
|
29
63
|
import { lineLook, restyleLines } from "./restyle.js";
|
|
30
64
|
import { KYOGIJO_MARK_STYLE } from "./mark.js";
|
|
31
|
-
import {
|
|
65
|
+
import { readSituation, situationSentences } from "./situation.js";
|
|
66
|
+
import { badgeSituation, drawSituation } from "./situation.draw.js";
|
|
67
|
+
import { KYOGIJO_SITUATION_STYLE } from "./situation.style.js";
|
|
68
|
+
import { outlineOf } from "./outline.js";
|
|
69
|
+
import { autoScore, pageantLayout, pageantOf, ratioOf } from "./pageant.js";
|
|
70
|
+
import { emblemMarkup, picturesMarkup } from "./pageant.draw.js";
|
|
71
|
+
import { KYOGIJO_PAGEANT_MOTION, KYOGIJO_PAGEANT_STYLE } from "./pageant.style.js";
|
|
72
|
+
import { KYOGIJO_BASE_STYLE, KYOGIJO_CURLING_STYLE, KYOGIJO_FOLD_STYLE, KYOGIJO_NOTE_STYLE, KYOGIJO_WALLS_STYLE } from "./style.js";
|
|
32
73
|
import { convertLength } from "./units.js";
|
|
33
|
-
import { baseball } from "./surfaces/baseball.js";
|
|
74
|
+
import { baseball, fenceOutline } from "./surfaces/baseball.js";
|
|
34
75
|
import { curling } from "./surfaces/curling.js";
|
|
35
76
|
import { netCourt } from "./surfaces/net.js";
|
|
36
77
|
import { fieldSurface } from "./surfaces/field.js";
|
|
37
78
|
import { basketball } from "./surfaces/basketball.js";
|
|
38
79
|
import { football } from "./surfaces/football.js";
|
|
39
80
|
import { hockey } from "./surfaces/hockey.js";
|
|
81
|
+
import { NHL_RINK } from "./leagues/hockey.js";
|
|
82
|
+
import { NBA_COURT } from "./leagues/basketball.js";
|
|
40
83
|
import { soccer } from "./surfaces/soccer.js";
|
|
41
84
|
import { frameMatrix, layoutFromFrame, resolveFrame } from "./surfaces/soccer-providers.js";
|
|
42
85
|
import { composeSpecial, hostSport } from "./special.js";
|
|
@@ -47,7 +90,7 @@ import { abbreviate, capitals } from "./text.js";
|
|
|
47
90
|
import { VERSION } from "./version.js";
|
|
48
91
|
export { isPortrait };
|
|
49
92
|
/** The sports that can be drawn, in the order a menu lists them. */
|
|
50
|
-
export const SPORTS = ["nfl", "cfl", "ifaf", "nhl", "nba", "mlb", "soccer", "curling", "tennis", "volleyball", "badminton", "pickleball", "tabletennis", "lacrosse", "rugby", "afl", "gaelic", "cricket", "fieldhockey", "handball"];
|
|
93
|
+
export const SPORTS = ["nfl", "cfl", "ifaf", "nhl", "nba", "mlb", "soccer", "curling", "tennis", "volleyball", "badminton", "pickleball", "tabletennis", "padel", "squash", "racquetball", "sepaktakraw", "teqball", "roundnet", "netball", "swimming", "waterpolo", "diving", "artisticswimming", "athletics", "skating", "judo", "karate", "kendo", "sumo", "kyudo", "dojo", "lacrosse", "rugby", "afl", "gaelic", "cricket", "fieldhockey", "handball"];
|
|
51
94
|
/** The CSS custom property each colour of `Colors` sets. */
|
|
52
95
|
export const COLOR_PROPERTIES = {
|
|
53
96
|
apron: "--ky-apron",
|
|
@@ -90,7 +133,8 @@ const isScore = (o) => o.home !== undefined && o.away !== undefined;
|
|
|
90
133
|
function minSets(sport, league) {
|
|
91
134
|
if (sport === "volleyball")
|
|
92
135
|
return league === "fivb-beach" ? 3 : 5;
|
|
93
|
-
|
|
136
|
+
// Table tennis, squash (World Squash Singles Rules 2.3) and racquetball (IRF Rule 1.5) are played to the best of five games.
|
|
137
|
+
return sport === "tabletennis" || sport === "squash" || sport === "racquetball" ? 5 : 3;
|
|
94
138
|
}
|
|
95
139
|
/** The standard statuses, spelled out. */
|
|
96
140
|
const FINAL = /^(?:final|f\b|ft\b|試合終了|終了)/i;
|
|
@@ -139,8 +183,8 @@ export function winnerOf(o) {
|
|
|
139
183
|
const mode = o.winner ?? "auto";
|
|
140
184
|
if (mode === "home" || mode === "away" || mode === "none")
|
|
141
185
|
return mode;
|
|
142
|
-
const h = fieldTotal(o.sport, o.home) ?? numeric(o.home.score);
|
|
143
|
-
const a = fieldTotal(o.sport, o.away) ?? numeric(o.away.score);
|
|
186
|
+
const h = fieldTotal(o.sport, o.home) ?? numeric(o.home.score) ?? (o.sport === undefined ? undefined : numeric(budoScoreText(o.sport, o.home)));
|
|
187
|
+
const a = fieldTotal(o.sport, o.away) ?? numeric(o.away.score) ?? (o.sport === undefined ? undefined : numeric(budoScoreText(o.sport, o.away)));
|
|
144
188
|
if (h === undefined || a === undefined)
|
|
145
189
|
return "none";
|
|
146
190
|
if (mode === "auto" && !(o.status !== undefined && FINAL.test(o.status.trim())))
|
|
@@ -177,7 +221,7 @@ const safeLength = (value) => {
|
|
|
177
221
|
const PATTERNS = ["bands", "wide", "narrow", "lengthwise", "checks", "diagonal", "circles", "rings", "fan", "none"];
|
|
178
222
|
const GOALS = ["box", "line", "strip", "none"];
|
|
179
223
|
/** The pitch the options ask for: a `pitch` of the caller's, else the size a `ground` publishes, else none (the international pitch). */
|
|
180
|
-
function pitchOf(o) {
|
|
224
|
+
export function pitchOf(o) {
|
|
181
225
|
if (o.pitch !== undefined)
|
|
182
226
|
return o.pitch;
|
|
183
227
|
const ground = groundById(o.ground);
|
|
@@ -199,10 +243,35 @@ function buildSoccer(o, common, scored, unit) {
|
|
|
199
243
|
frame: frame === undefined ? undefined : { id: frame.id, matrix: frameMatrix(frame, spec) },
|
|
200
244
|
}, common);
|
|
201
245
|
}
|
|
246
|
+
/** The athletics stadium: its plan, with the soccer pitch laid inside the track as the soccer builder draws it. */
|
|
247
|
+
function buildAthletics(o, common) {
|
|
248
|
+
const plan = athleticsPlan({ ...o, detail: common.detail });
|
|
249
|
+
let embedded;
|
|
250
|
+
if (plan.pitch !== undefined) {
|
|
251
|
+
const spec = plan.pitch.spec;
|
|
252
|
+
const goals = common.goals ?? "box";
|
|
253
|
+
const pitch = soccer({ spec, layout: layoutOf(spec), half: undefined, pattern: "bands", goals, flags: common.detail === "full", frame: undefined }, { ...common, portrait: false, margin: 0, score: false, landmarks: false, id: `${common.id}-pitch` });
|
|
254
|
+
embedded = { base: pitchGroup(pitch.base), lines: pitch.lines, defs: pitch.defs };
|
|
255
|
+
}
|
|
256
|
+
// A cropped view has less ground round it than the stadium whole.
|
|
257
|
+
return athleticsSurface(common, plan, embedded, common.margin ?? (o.range === undefined ? 20 : 5));
|
|
258
|
+
}
|
|
259
|
+
/** The skating rink: its plan, drawn as it lies. */
|
|
260
|
+
function buildSkating(o, common) {
|
|
261
|
+
const plan = skatingPlan({ ...o, detail: common.detail });
|
|
262
|
+
return skatingSurface(common, plan, common.margin ?? (o.range === undefined ? 20 : 5));
|
|
263
|
+
}
|
|
264
|
+
/** The budō surface: its plan, drawn as it lies. A hall, a kyūdōjō and a range of mats have little ground round them. */
|
|
265
|
+
function buildBudo(o, common) {
|
|
266
|
+
const plan = budoPlan({ ...o, detail: common.detail });
|
|
267
|
+
return budoSurface(common, plan, common.margin ?? (o.range === undefined ? 12 : 4));
|
|
268
|
+
}
|
|
269
|
+
/** One text for both ends or sides, or a pair of them. */
|
|
270
|
+
const pair = (text) => (text === undefined ? undefined : typeof text === "string" ? [text, text] : text);
|
|
202
271
|
/** The surface the options ask for, whole: before it is cropped to a `range`. */
|
|
203
272
|
function buildWhole(o, portrait, id, score, scored, extra) {
|
|
204
273
|
const court = o.court;
|
|
205
|
-
const baselineText = court?.baselineText
|
|
274
|
+
const baselineText = pair(court?.baselineText);
|
|
206
275
|
const unit = lengthUnit(o);
|
|
207
276
|
const common = {
|
|
208
277
|
portrait,
|
|
@@ -212,12 +281,13 @@ function buildWhole(o, portrait, id, score, scored, extra) {
|
|
|
212
281
|
stripes: o.stripes !== false,
|
|
213
282
|
id,
|
|
214
283
|
score,
|
|
215
|
-
court: { baselineText, centreLogo: safeLogo(court?.centreLogo), paintThreePoint: court?.paintThreePoint },
|
|
284
|
+
court: { baselineText, centreLogo: safeLogo(court?.centreLogo), paintThreePoint: court?.paintThreePoint, hardwood: resolveHardwood(court, o.detail === "simple", o.width), sidelineText: pair(court?.sidelineText) },
|
|
216
285
|
features: extra.features,
|
|
217
286
|
mow: PATTERNS.includes(o.stripePattern) ? o.stripePattern : undefined,
|
|
218
287
|
goals: GOALS.includes(o.goals) ? o.goals : undefined,
|
|
219
288
|
goalMarkup: typeof o.goalMarkup === "function" ? o.goalMarkup : undefined,
|
|
220
289
|
landmarks: o.landmarks === true,
|
|
290
|
+
pageant: extra.pageant === true ? true : undefined,
|
|
221
291
|
};
|
|
222
292
|
// A league's rulebook (`league`), else the markings of the season asked for (`year`), today's without one.
|
|
223
293
|
const { sport, league } = chooseLeague(o);
|
|
@@ -232,10 +302,19 @@ function buildWhole(o, portrait, id, score, scored, extra) {
|
|
|
232
302
|
const season = rulesFor(sport, o.year).rules;
|
|
233
303
|
return football(footballIn(sport, o.year), common, { hashMarks: season.hash !== null, postShape: season.postShape });
|
|
234
304
|
}
|
|
235
|
-
case "nhl":
|
|
305
|
+
case "nhl": {
|
|
306
|
+
// An arena's rink is the size its sources publish, with the markings of the season asked for; an arena with none published has the NHL's.
|
|
307
|
+
const sized = league === undefined ? arenaRinkIn(arenaById(o.arena), o.year) : undefined;
|
|
308
|
+
if (sized !== undefined)
|
|
309
|
+
return hockey(common, rulesFor("nhl", o.year).rules, { ...NHL_RINK, length: sized.length, width: sized.width });
|
|
236
310
|
return league?.family === "hockey" ? hockey(common, undefined, rinkOf(league, o.year)) : hockey(common, rulesFor("nhl", o.year).rules);
|
|
237
|
-
|
|
311
|
+
}
|
|
312
|
+
case "nba": {
|
|
313
|
+
const sized = league === undefined ? arenaCourtIn(arenaById(o.arena), o.year) : undefined;
|
|
314
|
+
if (sized !== undefined)
|
|
315
|
+
return basketball(common, rulesFor("nba", o.year).rules, { ...NBA_COURT, length: sized.length, width: sized.width });
|
|
238
316
|
return league?.family === "basketball" ? basketball(common, undefined, courtOf(league, o.year)) : basketball(common, rulesFor("nba", o.year).rules);
|
|
317
|
+
}
|
|
239
318
|
case "mlb": {
|
|
240
319
|
if (league?.family === "baseball") {
|
|
241
320
|
const diamond = diamondOf(league, o.year);
|
|
@@ -248,14 +327,33 @@ function buildWhole(o, portrait, id, score, scored, extra) {
|
|
|
248
327
|
case "curling": {
|
|
249
328
|
const plan = sheetFor(o);
|
|
250
329
|
// A score always shows the whole sheet, for the board's sake.
|
|
251
|
-
|
|
330
|
+
const words = KYOGIJO_STRINGS[o.language === "ja" ? "ja" : "en"].ranges.folded;
|
|
331
|
+
const labels = portrait ? [words.top, words.bottom] : [words.left, words.right];
|
|
332
|
+
return curling(common, { pebble: plan.pebble, guardZone: plan.guardZone, show: scored ? "sheet" : plan.show, end: plan.end, figures: plan.spec, fold: { panels: plan.panels, fit: plan.fit, labels } });
|
|
252
333
|
}
|
|
253
334
|
case "tennis":
|
|
254
335
|
case "volleyball":
|
|
255
336
|
case "badminton":
|
|
256
337
|
case "pickleball":
|
|
257
338
|
case "tabletennis":
|
|
339
|
+
case "padel":
|
|
340
|
+
case "squash":
|
|
341
|
+
case "racquetball":
|
|
342
|
+
case "sepaktakraw":
|
|
343
|
+
case "teqball":
|
|
344
|
+
case "roundnet":
|
|
345
|
+
case "netball":
|
|
258
346
|
return netCourt(common, courtFor({ ...o, sport }));
|
|
347
|
+
case "swimming":
|
|
348
|
+
if (o.pool?.venue !== undefined)
|
|
349
|
+
return natatorium(common, o.pool, commonOf(o.pool), o.language === "ja" ? "ja" : "en");
|
|
350
|
+
return swimming(common, swimPlan({ ...o, sport }));
|
|
351
|
+
case "waterpolo":
|
|
352
|
+
return waterPolo(common, poloPlan(o));
|
|
353
|
+
case "diving":
|
|
354
|
+
return diving(common, divePlan(o));
|
|
355
|
+
case "artisticswimming":
|
|
356
|
+
return artistic(common, artisticPlan(o));
|
|
259
357
|
case "lacrosse":
|
|
260
358
|
case "rugby":
|
|
261
359
|
case "afl":
|
|
@@ -264,18 +362,103 @@ function buildWhole(o, portrait, id, score, scored, extra) {
|
|
|
264
362
|
case "fieldhockey":
|
|
265
363
|
case "handball":
|
|
266
364
|
return fieldSurface(common, fieldPlan({ ...o, sport, detail: common.detail }), { goals: common.goals });
|
|
365
|
+
case "athletics":
|
|
366
|
+
return buildAthletics({ ...o, sport }, common);
|
|
367
|
+
case "skating":
|
|
368
|
+
return buildSkating({ ...o, sport }, common);
|
|
369
|
+
case "judo":
|
|
370
|
+
case "karate":
|
|
371
|
+
case "kendo":
|
|
372
|
+
case "sumo":
|
|
373
|
+
case "kyudo":
|
|
374
|
+
case "dojo":
|
|
375
|
+
return buildBudo({ ...o, sport }, common);
|
|
267
376
|
default:
|
|
268
377
|
throw new Error(`Unknown sport "${String(o.sport)}": use one of ${SPORTS.join(", ")}`);
|
|
269
378
|
}
|
|
270
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* The crowd the options ask for, or `undefined` for none: a special game has none, and nor has a folded curling sheet (its houses are enlarged over where the stands would be, so the
|
|
382
|
+
* stands would show only as strips behind the panels). A score on a curling sheet shows the whole sheet, which has its stands.
|
|
383
|
+
*/
|
|
384
|
+
function crowdOf(o) {
|
|
385
|
+
if (o.host !== undefined)
|
|
386
|
+
return undefined;
|
|
387
|
+
if (chooseLeague(o).sport === "curling" && !isScore(o) && sheetFor(o).show === "folded")
|
|
388
|
+
return undefined;
|
|
389
|
+
return resolveCrowd(o.crowd);
|
|
390
|
+
}
|
|
271
391
|
/** The surface the options ask for, cropped to their `range` when they have one (a curling sheet's named ranges are its builder's own: `sheet.show`). */
|
|
272
392
|
function buildSurface(o, portrait, id, score, scored, extra) {
|
|
273
|
-
const
|
|
393
|
+
const crowd = crowdOf(o);
|
|
394
|
+
const surface = crowd === undefined ? buildWhole(o, portrait, id, score, scored, extra) : buildCrowded(o, portrait, id, score, scored, extra, crowd);
|
|
274
395
|
// A score on a curling sheet shows all of it, for the board's sake.
|
|
275
396
|
if (o.range === undefined || (scored && chooseLeague(o).sport === "curling"))
|
|
276
397
|
return surface;
|
|
398
|
+
// A close-up of a start is the athletics builder's own view, turned to the start's line.
|
|
399
|
+
if (chooseLeague(o).sport === "athletics" && rangeLabel(o) === "start")
|
|
400
|
+
return surface;
|
|
277
401
|
const given = typeof o.margin === "number" && Number.isFinite(o.margin) && o.margin >= 0 ? convertLength(o.margin, lengthUnit(o), "ft") : undefined;
|
|
278
|
-
return cropToRange(surface, o, { id, margin: extra.room ?? extra.margin ?? given, panel: score });
|
|
402
|
+
return cropToRange(surface, o, { id, margin: extra.room ?? extra.margin ?? given ?? surface.crowdMargin, panel: score });
|
|
403
|
+
}
|
|
404
|
+
/** The fence of the ballpark the options ask for, as the drawing has it, and how far behind home plate the backstop stands. */
|
|
405
|
+
function parkFence(o) {
|
|
406
|
+
const unit = lengthUnit(o);
|
|
407
|
+
const { league } = chooseLeague(o);
|
|
408
|
+
if (league?.family === "baseball") {
|
|
409
|
+
const diamond = diamondOf(league, o.year);
|
|
410
|
+
return { points: fenceFor(parkById(o.park), feetFence(o.fence, unit), o.year, diamondFence(diamond)), backstop: diamond.backstop };
|
|
411
|
+
}
|
|
412
|
+
return { points: fenceFor(parkById(o.park), feetFence(o.fence, unit), o.year), backstop: MLB_DIAMOND.backstop };
|
|
413
|
+
}
|
|
414
|
+
/** The stands round a surface, laid out from its box (or, for a ballpark, from its fence). */
|
|
415
|
+
function standsFor(o, surface, crowd) {
|
|
416
|
+
const { sport } = chooseLeague(o);
|
|
417
|
+
const awaySide = resolveHomeSide({ ...o, sport }) === "left" ? "right" : "left";
|
|
418
|
+
if (sport === "mlb") {
|
|
419
|
+
const { points, backstop } = parkFence(o);
|
|
420
|
+
// The walls that have seats on top of them: the ones the package knows (Fenway Park's Green Monster), or, asked for, every wall of 25 feet or more.
|
|
421
|
+
const park = parkById(o.park);
|
|
422
|
+
const walls = park === undefined || crowd.wallSeats === false ? [] : parkWallsIn(park, o.year).filter((w) => (crowd.wallSeats === true ? w.height_ft >= 25 : w.label !== undefined && WALL_SEATS[park.id] === w.label));
|
|
423
|
+
return parkLayout({ fence: fenceOutline(points), backstop, crowd, seatsOnWalls: walls.map((w) => ({ from: w.from, to: w.to, height: w.height_ft })) });
|
|
424
|
+
}
|
|
425
|
+
// 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
|
+
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
|
+
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
|
+
/** True when the drawing is asked to be small: `detail: "simple"` or a `width` under 480 pixels. */
|
|
431
|
+
const smallDrawing = (o) => {
|
|
432
|
+
const w = typeof o.width === "number" ? o.width : typeof o.width === "string" && /^\s*\d+(?:\.\d+)?(?:px)?\s*$/.test(o.width) ? parseFloat(o.width) : undefined;
|
|
433
|
+
return o.detail === "simple" || (w !== undefined && w < 480);
|
|
434
|
+
};
|
|
435
|
+
/** A surface with the stands and the crowd round it: the ground is made as wide as the stands need, then the stands are laid on it under the surface. */
|
|
436
|
+
function buildCrowded(o, portrait, id, score, scored, extra, crowd) {
|
|
437
|
+
let margin = extra.margin;
|
|
438
|
+
if (!(typeof o.margin === "number" && Number.isFinite(o.margin) && o.margin >= 0)) {
|
|
439
|
+
// How much ground the stands need beyond what the surface has with none, then the surface is made again with it.
|
|
440
|
+
const probe = buildWhole({ ...o, margin: 0 }, portrait, id, score, scored, { ...extra, margin: undefined });
|
|
441
|
+
const stands = standsFor(o, probe, crowd);
|
|
442
|
+
const view = wideView(probe);
|
|
443
|
+
const have = { left: stands.box.x - view.x, right: view.x + view.w - stands.box.x - stands.box.w, top: stands.box.y - view.y, bottom: view.y + view.h - stands.box.y - stands.box.h };
|
|
444
|
+
const need = Math.max(stands.reach.left - have.left, stands.reach.right - have.right, stands.reach.top - have.top, stands.reach.bottom - have.bottom);
|
|
445
|
+
margin = Math.max(margin ?? 0, need + 6);
|
|
446
|
+
}
|
|
447
|
+
const surface = buildWhole(o, portrait, id, score, scored, { ...extra, margin });
|
|
448
|
+
const stands = standsFor(o, surface, crowd);
|
|
449
|
+
const seats = stands.seats;
|
|
450
|
+
const ground = groundById(o.ground)?.capacity;
|
|
451
|
+
const fine = crowd.detail === "fine" || (crowd.detail === "auto" && !smallDrawing(o));
|
|
452
|
+
const first = /^<[^>]*\/>/.exec(surface.base)?.[0] ?? "";
|
|
453
|
+
const bg = /class="([^"]*)"/.exec(first)?.[1] ?? "ky-apron";
|
|
454
|
+
// A gallery is sparsely taken unless the options say how full.
|
|
455
|
+
const taken = stands.gallery === true && crowd.density === undefined && crowd.attendance === undefined ? 0.4 : densityOf(crowd, seats, ground);
|
|
456
|
+
const drawn = drawCrowd(stands, { id, crowd, density: taken, fine, ground: bg });
|
|
457
|
+
surface.base = first + drawn.markup + surface.base.slice(first.length);
|
|
458
|
+
surface.defs += drawn.defs;
|
|
459
|
+
surface.lines += drawn.over;
|
|
460
|
+
surface.crowdMargin = margin;
|
|
461
|
+
return surface;
|
|
279
462
|
}
|
|
280
463
|
/** The custom properties a drawing sets on its root, from the options' colours. */
|
|
281
464
|
function colourStyle(o, teams, features) {
|
|
@@ -287,6 +470,13 @@ function colourStyle(o, teams, features) {
|
|
|
287
470
|
};
|
|
288
471
|
for (const [key, property] of Object.entries(COLOR_PROPERTIES))
|
|
289
472
|
set(property, o.colors?.[key]);
|
|
473
|
+
// A dojo's own colours (and its era's): the mats, the second tone, the border, the heri, the wood and the walls.
|
|
474
|
+
if (o.sport === "dojo" && o.dojo !== undefined) {
|
|
475
|
+
const c = dojoSpecOf(o.dojo).colours;
|
|
476
|
+
if (c !== undefined)
|
|
477
|
+
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
|
+
set(property, c[key]);
|
|
479
|
+
}
|
|
290
480
|
if (o.court !== undefined)
|
|
291
481
|
for (const [key, property] of Object.entries(COURT_PROPERTIES))
|
|
292
482
|
set(property, o.court[key]);
|
|
@@ -315,6 +505,23 @@ function colourStyle(o, teams, features) {
|
|
|
315
505
|
props.push(`--ky-left-ink:${leftInk}`);
|
|
316
506
|
if (rightInk !== undefined)
|
|
317
507
|
props.push(`--ky-right-ink:${rightInk}`);
|
|
508
|
+
// A hardwood floor's border behind each baseline: the court's colour for it, else the team's, else the border's.
|
|
509
|
+
if (o.court?.hardwood !== undefined && o.court.hardwood !== false) {
|
|
510
|
+
const ends = pair(o.court.baselineColor);
|
|
511
|
+
const endLeft = safeColour(ends?.[0]) ?? left;
|
|
512
|
+
const endRight = safeColour(ends?.[1]) ?? right;
|
|
513
|
+
if (endLeft !== undefined)
|
|
514
|
+
props.push(`--ky-hw-end-left:${endLeft}`);
|
|
515
|
+
if (endRight !== undefined)
|
|
516
|
+
props.push(`--ky-hw-end-right:${endRight}`);
|
|
517
|
+
}
|
|
518
|
+
// The crowd's colours: the home fans in the home team's colour and the visitors in the other's, or the colours the crowd names.
|
|
519
|
+
const crowd = crowdOf(o);
|
|
520
|
+
if (crowd !== undefined) {
|
|
521
|
+
const homeLeft = resolveHomeSide({ ...o, sport: chooseLeague(o).sport }) === "left";
|
|
522
|
+
props.push(`--ky-cr-home:${safeColour(crowd.home) ?? (homeLeft ? left : right) ?? `var(--ky-${homeLeft ? "left" : "right"})`}`);
|
|
523
|
+
props.push(`--ky-cr-away:${safeColour(crowd.away) ?? (homeLeft ? right : left) ?? `var(--ky-${homeLeft ? "right" : "left"})`}`);
|
|
524
|
+
}
|
|
318
525
|
return props.join(";");
|
|
319
526
|
}
|
|
320
527
|
/** The round mark of a team, when its own `mark` or the score's `markShape` asks for one: the fit, the colour of its disc and the ink of its initials. */
|
|
@@ -324,17 +531,18 @@ function roundOf(team, markShape) {
|
|
|
324
531
|
return undefined;
|
|
325
532
|
return { round: true, fit: team.markFit === "contain" ? "contain" : undefined, color: safeColour(team.color), ink: safeColour(team.textColor) };
|
|
326
533
|
}
|
|
327
|
-
function teamView(team, side, role, winner, uppercase, sport, markShape) {
|
|
534
|
+
function teamView(team, side, role, winner, uppercase, sport, markShape, theme) {
|
|
328
535
|
const name = String(team.name ?? "");
|
|
329
|
-
const
|
|
536
|
+
const abbr = (team.abbr !== undefined && team.abbr.trim() !== "" ? team.abbr.trim() : abbreviate(name)).slice(0, 5);
|
|
537
|
+
const written = fieldScoreText(sport, team) ?? budoScoreText(sport, team);
|
|
330
538
|
const score = written ?? (team.score === undefined || team.score === null || String(team.score).trim() === "" ? "–" : String(team.score));
|
|
331
539
|
return {
|
|
332
540
|
side,
|
|
333
541
|
role,
|
|
334
542
|
name: uppercase ? capitals(name) : name,
|
|
335
|
-
abbr
|
|
543
|
+
abbr,
|
|
336
544
|
score,
|
|
337
|
-
logo: safeLogo(team.logo),
|
|
545
|
+
logo: safeLogo(team.logo, { color: team.color, accent: team.textColor, initials: abbr.slice(0, 3), theme }),
|
|
338
546
|
...roundOf(team, markShape),
|
|
339
547
|
state: stateOf(winner, role),
|
|
340
548
|
ends: Array.isArray(team.ends) ? team.ends.map(endText) : undefined,
|
|
@@ -345,13 +553,52 @@ function teamView(team, side, role, winner, uppercase, sport, markShape) {
|
|
|
345
553
|
serving: team.serving === true ? true : undefined,
|
|
346
554
|
wickets: sport === "cricket" && team.wickets !== undefined && team.wickets !== null && String(team.wickets).trim() !== "" ? String(team.wickets).trim().slice(0, 2) : undefined,
|
|
347
555
|
overs: sport === "cricket" && team.overs !== undefined && team.overs !== null && String(team.overs).trim() !== "" ? String(team.overs).trim().slice(0, 6) : undefined,
|
|
556
|
+
budo: isBudoSport(sport) ? budoView(team.budo) : undefined,
|
|
348
557
|
innings: sport === "cricket" && Array.isArray(team.innings) ? team.innings.map((value) => (typeof value === "number" ? (Number.isFinite(value) ? String(value) : "") : typeof value === "string" ? value.trim().slice(0, 7) : "")) : undefined,
|
|
349
558
|
};
|
|
350
559
|
}
|
|
560
|
+
/** A team as the pageant lays it out. */
|
|
561
|
+
function pageantTeam(view, team) {
|
|
562
|
+
return { side: view.side, role: view.role, name: view.name, abbr: view.abbr, state: view.state, href: view.logo, fit: team.markFit === "contain" ? "contain" : "cover", ratio: ratioOf(team), color: safeColour(team.color), ink: safeColour(team.textColor) };
|
|
563
|
+
}
|
|
564
|
+
/** 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
|
+
function tiny(width) {
|
|
566
|
+
const px = typeof width === "number" ? width : typeof width === "string" && /^\d+(?:\.\d+)?(?:px)?$/.test(width.trim()) ? Number.parseFloat(width) : undefined;
|
|
567
|
+
return px !== undefined && Number.isFinite(px) && px < 320;
|
|
568
|
+
}
|
|
569
|
+
/** 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);
|
|
573
|
+
return surface.pageant?.byRole === true && l.role === "home" ? [r, l] : [l, r];
|
|
574
|
+
}
|
|
575
|
+
function pageantParts(o, surface, p, t) {
|
|
576
|
+
const [first, second] = pageantPair(surface, t);
|
|
577
|
+
const layout = pageantLayout({ pageant: p, surface, outline: outlineOf(o), left: first, right: second, turned: surface.turned, sport: t.sport, plate: t.plate });
|
|
578
|
+
if (layout === undefined)
|
|
579
|
+
return undefined;
|
|
580
|
+
// Cropped to a range, an emblem that does not lie wholly in what is shown is left out.
|
|
581
|
+
const shown = surface.whole === undefined ? undefined : surface.box;
|
|
582
|
+
if (layout.emblem !== undefined && shown !== undefined) {
|
|
583
|
+
const e = layout.emblem;
|
|
584
|
+
if (e.cx - e.r < shown.x || e.cx + e.r > shown.x + shown.w || e.cy - e.r < shown.y || e.cy + e.r > shown.y + shown.h)
|
|
585
|
+
delete layout.emblem;
|
|
586
|
+
}
|
|
587
|
+
const draw = { id: t.id, turned: surface.turned, simple: o.detail === "simple" || tiny(o.width), parts: t.parts };
|
|
588
|
+
const pictures = picturesMarkup(layout, p, draw);
|
|
589
|
+
const emblem = emblemMarkup(layout, p, draw);
|
|
590
|
+
return { pictures: pictures.markup, names: pictures.names, emblem: emblem.markup, defs: pictures.defs + emblem.defs, plateScale: layout.plateScale };
|
|
591
|
+
}
|
|
351
592
|
const trimmed = (value) => String(Math.round(value * 100) / 100);
|
|
352
593
|
/** What a league's surface is, in a sentence fragment: its size or its bases, from the league's own figures in the unit its rulebook uses. */
|
|
353
594
|
function leagueAbout(league, year, language, sheet) {
|
|
354
595
|
const words = KYOGIJO_STRINGS[language].league;
|
|
596
|
+
if (league.family === "skating")
|
|
597
|
+
return skatingAbout({ sport: "skating", league: league.id }, language);
|
|
598
|
+
if (league.family === "judo" || league.family === "karate" || league.family === "kendo" || league.family === "sumo" || league.family === "kyudo" || league.family === "dojo")
|
|
599
|
+
return budoAbout({ sport: league.family, league: league.id }, language);
|
|
600
|
+
if (league.family === "athletics")
|
|
601
|
+
return athleticsAbout({ sport: "athletics", league: league.id, athletics: sheet === undefined ? undefined : undefined }, language);
|
|
355
602
|
// The field sports: their size is the surface drawn (the one the options ask for), in the unit their rulebook prints first.
|
|
356
603
|
if (league.family === "lacrosse" || league.family === "rugby" || league.family === "afl" || league.family === "gaelic" || league.family === "cricket" || league.family === "fieldhockey" || league.family === "handball") {
|
|
357
604
|
const sized = sheet ?? leagueSize(league.family, league.id);
|
|
@@ -370,7 +617,7 @@ function leagueAbout(league, year, language, sheet) {
|
|
|
370
617
|
? rinkOf(league, year)
|
|
371
618
|
: league.family === "curling"
|
|
372
619
|
? (sheet ?? sheetOf(league))
|
|
373
|
-
: league
|
|
620
|
+
: isNetLeague(league)
|
|
374
621
|
? (() => {
|
|
375
622
|
const f = netOf(league);
|
|
376
623
|
return { length: f.length, width: f.widthDoubles ?? f.width };
|
|
@@ -381,7 +628,29 @@ function leagueAbout(league, year, language, sheet) {
|
|
|
381
628
|
})();
|
|
382
629
|
const to = league.unit;
|
|
383
630
|
const text = fill(words.size, { length: trimmed(convertLength(size.length, "ft", to)), width: trimmed(convertLength(size.width, "ft", to)), unit: words.units[to === "m" || to === "yd" ? to : "ft"] });
|
|
384
|
-
return fill(league.family === "volleyball" && league.id === "fivb-beach" ? words.beachVolleyball : words[league.family], { size: text });
|
|
631
|
+
return fill(league.family === "volleyball" && league.id === "fivb-beach" ? words.beachVolleyball : league.family === "volleyball" && league.id === "wpv-sitting" ? words.sittingVolleyball : words[league.family], { size: text });
|
|
632
|
+
}
|
|
633
|
+
/** The football field a drawing is on, for a situation to know the yards between the goal lines and the downs a team has (the CFL's three). */
|
|
634
|
+
function footballFieldOf(o, sport, league) {
|
|
635
|
+
if (sport !== "nfl" && sport !== "cfl" && sport !== "ifaf")
|
|
636
|
+
return undefined;
|
|
637
|
+
const spec = league?.family === "football" ? fieldOf(league, o.year) : sport === "ifaf" ? FOOTBALL.ifaf : footballIn(sport, o.year);
|
|
638
|
+
return { yards: spec.length / 3, downs: spec.id === "cfl" ? 3 : 4 };
|
|
639
|
+
}
|
|
640
|
+
/** The situation the options ask for, read: which team attacks, which end, what is lit. `undefined` for none, for a sport that has no situation and for a special game. */
|
|
641
|
+
function situationOf(o) {
|
|
642
|
+
if (o.situation === undefined || o.host !== undefined)
|
|
643
|
+
return undefined;
|
|
644
|
+
const { sport, league } = chooseLeague(o);
|
|
645
|
+
const ctx = {
|
|
646
|
+
sport,
|
|
647
|
+
homeSide: resolveHomeSide({ ...o, sport }),
|
|
648
|
+
direction: o.direction,
|
|
649
|
+
football: footballFieldOf(o, sport, league),
|
|
650
|
+
names: isScore(o) ? { home: String(o.home.name ?? ""), away: String(o.away.name ?? "") } : undefined,
|
|
651
|
+
league: league?.id,
|
|
652
|
+
};
|
|
653
|
+
return readSituation(o.situation, ctx);
|
|
385
654
|
}
|
|
386
655
|
/** A drawing's title and description, in a language. */
|
|
387
656
|
export function describe(o) {
|
|
@@ -398,15 +667,25 @@ export function describe(o) {
|
|
|
398
667
|
const ground = pitch?.format === "11" ? groundById(o.ground) : undefined;
|
|
399
668
|
const groundName = ground === undefined ? undefined : groundNameIn(ground, o.year, language);
|
|
400
669
|
// A league other than the sport's own is named by its rulebook's, and its description is made from its figures.
|
|
401
|
-
const
|
|
670
|
+
const trackGround = sport === "athletics" ? groundById(o.ground) : undefined;
|
|
671
|
+
const trackGroundName = trackGround === undefined ? undefined : groundNameIn(trackGround, o.year, language);
|
|
672
|
+
// An arena names its rink or its court.
|
|
673
|
+
const arena = (sport === "nhl" || sport === "nba") && league === undefined ? arenaById(o.arena) : undefined;
|
|
674
|
+
const arenaName = arena === undefined ? undefined : arenaNameIn(arena, o.year, language);
|
|
675
|
+
const arenaSize = arena === undefined || arenaName === undefined ? undefined : sport === "nhl" ? arenaRinkIn(arena, o.year) : arenaCourtIn(arena, o.year);
|
|
676
|
+
const surfaceName = arenaName !== undefined ? fill(sport === "nhl" ? words.said.arenaRink : words.said.arenaCourt, { arena: arenaName }) : trackGroundName !== undefined ? fill(words.athletics.ground, { ground: trackGroundName }) : groundName !== undefined ? (language === "ja" ? `${groundName}のピッチ` : `${groundName}, soccer pitch`) : league !== undefined && parkName === undefined ? league.name[language] : parkName === undefined ? (pitch?.format === "futsal" ? words.soccer.futsal : words.surface[sport]) : language === "ja" ? `${parkName}のグラウンド` : `${parkName}, baseball field`;
|
|
402
677
|
const { stop, colon, gap } = words.said;
|
|
403
678
|
const sentence = (text) => (/[.。]$/.test(text) ? text : `${text}${stop}`);
|
|
404
679
|
const metres = (value) => String(Math.round(value * 10) / 10);
|
|
405
680
|
const plan = sport === "curling" ? sheetFor(o) : undefined;
|
|
406
681
|
// A field sport: the surface as drawn, at the size the options ask for.
|
|
407
682
|
const field = isFieldSport(sport) ? fieldPlan({ ...o, sport }) : undefined;
|
|
408
|
-
const
|
|
409
|
-
const
|
|
683
|
+
const pools = isPoolSport(sport) ? poolDescription({ sport, pool: o.pool }, language) : undefined;
|
|
684
|
+
const poolLine = pools === undefined ? "" : pools.after.map((line) => `${gap}${line}`).join("");
|
|
685
|
+
// An arena of a size of its own says what it is at that size.
|
|
686
|
+
const arenaAbout = arenaSize === undefined ? undefined : fill(sport === "nhl" ? words.said.arenaRinkAbout : words.said.arenaCourtAbout, { length: metres(arenaSize.length), width: metres(arenaSize.width), lengthM: metres(arenaSize.length * 0.3048), widthM: metres(arenaSize.width * 0.3048) });
|
|
687
|
+
const aboutText = arenaAbout !== undefined ? arenaAbout : pools !== undefined ? pools.about : isBudoSport(sport) ? budoAbout(o, language) : sport === "skating" ? skatingAbout(o, language) : sport === "athletics" ? athleticsAbout(o, language) : field !== undefined ? leagueAbout(league ?? LEAGUES[sport][0], o.year, language, { length: field.length, width: field.width }) : plan !== undefined ? leagueAbout(plan.league, o.year, language, plan.spec) : league !== undefined ? leagueAbout(league, o.year, language) : pitch === undefined ? words.about[sport] : fill(pitch.format === "futsal" ? words.soccer.aboutFutsal : words.about.soccer, { length: metres(pitch.length), width: metres(pitch.width) });
|
|
688
|
+
const about = `${words.said.on}${colon}${aboutText}${stop}${sport === "athletics" ? athleticsSentences(o, language) : sport === "skating" ? skatingSentences(o, language) : isBudoSport(sport) ? budoSentences(o, language) : ""}`;
|
|
410
689
|
const halfLine = pitch !== undefined && !isScore(o) && (o.half === "left" || o.half === "right") ? `${gap}${words.soccer.half}` : "";
|
|
411
690
|
// What the ground says about the size: that it is the published one, or that the ground has none and the international pitch is drawn.
|
|
412
691
|
const year = typeof o.year === "number" && Number.isFinite(o.year) ? o.year : undefined;
|
|
@@ -417,7 +696,9 @@ export function describe(o) {
|
|
|
417
696
|
// A park's walls and quirks that are drawn are said too.
|
|
418
697
|
const ballpark = park === undefined ? undefined : ballparkFor(o);
|
|
419
698
|
const special = specialText(o, language, surfaceName);
|
|
420
|
-
|
|
699
|
+
// What the arena says about the size: that it is the one its sources publish, or that its rink is said to have been shorter and no size is given.
|
|
700
|
+
const arenaLine = arenaName === undefined ? "" : `${arenaSize !== undefined ? `${gap}${fill(words.said.arenaSize, { arena: arenaName })}` : sport === "nhl" && arena?.rinkUnknown === true ? `${gap}${fill(words.said.arenaUnknown, { arena: arenaName })}` : ""}${officially(arena === undefined ? undefined : arenaOfficialName(arena, language, year))}`;
|
|
701
|
+
const parkLine = (parkName === undefined ? `${groundLine}${halfLine}${arenaLine}` : `${gap}${fill(words.said.park, { park: parkName })}${officially(parkOfficial)}${ballpark === undefined ? "" : ballparkSentences(ballpark).map((line) => `${gap}${line}`).join("")}`) + (special === undefined ? "" : `${gap}${special.text}`);
|
|
421
702
|
// A drawing of a past season says which: the markings are those of that season.
|
|
422
703
|
const dated = typeof o.year === "number" && Number.isFinite(o.year);
|
|
423
704
|
const eraLine = dated && league !== undefined
|
|
@@ -428,11 +709,25 @@ export function describe(o) {
|
|
|
428
709
|
? `${gap}${fill(words.said.era, { season: seasonLabel(sport, o.year) })}`
|
|
429
710
|
: "";
|
|
430
711
|
// A range says what is shown; a curling score shows all of the sheet, whatever the range.
|
|
431
|
-
const
|
|
712
|
+
const hasData = o.layers !== undefined && o.layers.length > 0;
|
|
713
|
+
// A folded sheet says what is enlarged and where, in place of the range's own sentence.
|
|
714
|
+
const foldedWords = words.ranges.folded;
|
|
715
|
+
const rangeLine = isScore(o) && sport === "curling"
|
|
716
|
+
? ""
|
|
717
|
+
: plan?.show === "folded"
|
|
718
|
+
? `${gap}${[foldedWords[isPortrait(o) ? "tall" : "wide"], foldedWords[plan.panels], hasData ? foldedWords.data : ""].filter((part) => part !== "").join(gap)}`
|
|
719
|
+
: describeRange(o, language, hasData);
|
|
720
|
+
// A situation says what the pill, the lit bases or the line of scrimmage show.
|
|
721
|
+
const read = situationOf(o);
|
|
722
|
+
const situationLine = read === undefined ? "" : situationSentences(read, language, isScore(o) ? { home: o.home.name, away: o.away.name } : undefined).map((line) => `${gap}${line}`).join("");
|
|
432
723
|
if (!isScore(o))
|
|
433
|
-
return { title: o.title ?? special?.title ?? surfaceName, description: o.description ?? `${about}${parkLine}${eraLine}${rangeLine}` };
|
|
724
|
+
return { title: o.title ?? special?.title ?? surfaceName, description: o.description ?? `${about}${parkLine}${eraLine}${rangeLine}${situationLine}${poolLine}` };
|
|
434
725
|
const winner = winnerOf({ ...o, sport });
|
|
435
|
-
|
|
726
|
+
// A pageant says what lies on each half, and the emblem in the middle.
|
|
727
|
+
const pageant = pageantOf(o);
|
|
728
|
+
const pg = KYOGIJO_STRINGS[language].pageant;
|
|
729
|
+
const pageantLine = pageant === undefined ? "" : `${gap}${pageant.style === "stage" ? pg.stage : pg.carpet}${pageant.emblem === undefined ? "" : `${gap}${pageant.emblem.name === undefined ? pg.emblem : fill(pg.emblemNamed, { name: pageant.emblem.name })}`}`;
|
|
730
|
+
const s = (t) => fieldScoreText(sport, t) ?? budoScoreText(sport, t) ?? (t.score === undefined || String(t.score) === "" ? "–" : String(t.score));
|
|
436
731
|
// The sentence follows the drawing: the team on the left is first. The words' {away} and {home} are the first and the second team named.
|
|
437
732
|
const order = resolveHomeSide({ ...o, sport }) === "left" ? [o.home, o.away] : [o.away, o.home];
|
|
438
733
|
const line = fill(words.scoreTitle, { away: order[0].name, awayScore: s(order[0]), home: order[1].name, homeScore: s(order[1]) });
|
|
@@ -463,12 +758,12 @@ export function describe(o) {
|
|
|
463
758
|
const tb = endText(team.tiebreaks?.[i]);
|
|
464
759
|
return `${endText(value) || "–"}${tb === "" ? "" : ` (${tb})`}`;
|
|
465
760
|
}).join(words.layers.listSep);
|
|
466
|
-
const netLine = !
|
|
761
|
+
const netLine = !hasSetsBoard(sport)
|
|
467
762
|
? ""
|
|
468
763
|
: order
|
|
469
764
|
.flatMap((team) => [
|
|
470
765
|
team.serving === true ? fill(net.serving, { name: team.name }) : "",
|
|
471
|
-
Array.isArray(team.sets) && team.sets.length > 0 ? fill(sport === "
|
|
766
|
+
Array.isArray(team.sets) && team.sets.length > 0 ? fill(BOARD[sport] === "games" ? net.byGame : net.bySet, { name: team.name, list: setList(team) }) : "",
|
|
472
767
|
team.points !== undefined && team.points !== null && String(team.points).trim() !== "" ? fill(net.gamePoints, { name: team.name, points: String(team.points).trim() }) : "",
|
|
473
768
|
])
|
|
474
769
|
.filter((part) => part !== "")
|
|
@@ -493,7 +788,7 @@ export function describe(o) {
|
|
|
493
788
|
: "";
|
|
494
789
|
return {
|
|
495
790
|
title: o.title ?? (status === undefined ? line : `${line}${words.said.sep}${status}`),
|
|
496
|
-
description: o.description ?? `${extra === "" ? "" : `${sentence(extra)}${gap}`}${sentence(line)}${result}${tied}${curlingLine}${netLine}${fieldLine}${gap}${about}${parkLine}${eraLine}${rangeLine}`.trim(),
|
|
791
|
+
description: o.description ?? `${extra === "" ? "" : `${sentence(extra)}${gap}`}${sentence(line)}${result}${tied}${curlingLine}${netLine}${fieldLine}${isBudoSport(sport) ? budoScoreSentences(sport, order, language) : ""}${gap}${about}${parkLine}${eraLine}${rangeLine}${situationLine}${pageantLine}${poolLine}`.trim(),
|
|
497
792
|
};
|
|
498
793
|
}
|
|
499
794
|
/**
|
|
@@ -513,8 +808,14 @@ export function describe(o) {
|
|
|
513
808
|
* ```
|
|
514
809
|
*/
|
|
515
810
|
export function drawKyogijo(o) {
|
|
811
|
+
return withEmblems(o.emblems, () => drawnKyogijo(o));
|
|
812
|
+
}
|
|
813
|
+
function drawnKyogijo(o) {
|
|
516
814
|
if (o.host !== undefined && o.range !== undefined)
|
|
517
815
|
return drawKyogijo({ ...o, range: undefined });
|
|
816
|
+
// A special game is a surface set inside another, drawn to scale with no stands.
|
|
817
|
+
if (o.host !== undefined && o.crowd !== undefined)
|
|
818
|
+
return drawKyogijo({ ...o, crowd: undefined });
|
|
518
819
|
const language = o.language === "ja" ? "ja" : "en";
|
|
519
820
|
// The sport as drawn: a league that is a sport of its own (`league: "cfl"` on an `nfl`) is that sport.
|
|
520
821
|
const { sport } = chooseLeague(o);
|
|
@@ -526,7 +827,23 @@ export function drawKyogijo(o) {
|
|
|
526
827
|
// A tall curling sheet is 30 feet wide on the page and a strip under it would be unreadable: its compact size is the board on the ice.
|
|
527
828
|
const asked = isScore(o) ? (o.size === "compact" || o.size === "badge" ? o.size : "full") : "full";
|
|
528
829
|
let sized = asked === "compact" && sport === "curling" && portrait ? "full" : asked;
|
|
529
|
-
|
|
830
|
+
// A pageant that sends the score to the strip makes the drawing compact; a tall curling sheet cannot have a strip, so its board stays in the middle and the emblem is left out.
|
|
831
|
+
let pageant = isScore(o) ? pageantOf(o) : undefined;
|
|
832
|
+
if (pageant !== undefined && pageant.score === "strip") {
|
|
833
|
+
if (sport === "curling" && portrait)
|
|
834
|
+
pageant = { ...pageant, score: "centre", emblem: undefined };
|
|
835
|
+
else if (sized === "full")
|
|
836
|
+
sized = "compact";
|
|
837
|
+
}
|
|
838
|
+
// A lineup's players stand in the middle of the surface, where the score's panel would hide them: the score goes to the strip under the drawing, as a pageant's does, unless `score: "centre"` asks for it.
|
|
839
|
+
const lineupped = (o.layers ?? []).some((layer) => layer?.kind === "lineup");
|
|
840
|
+
const stripped = isScore(o) && lineupped && o.score !== "centre";
|
|
841
|
+
if (isScore(o) && pageant === undefined && sized === "full" && (o.score === "strip" || stripped) && !(sport === "curling" && portrait))
|
|
842
|
+
sized = "compact";
|
|
843
|
+
// The situation of the game (hockey's skaters, baseball's runners, football's down), decided once: the surface, the badge and the description draw from it.
|
|
844
|
+
const situation = situationOf(o);
|
|
845
|
+
// A situation that is not drawn (a sport that has none, nothing the sport can have in it) leaves the drawing, its ids included, as it was.
|
|
846
|
+
const id = drawingId(o.situation !== undefined && situation === undefined ? { ...o, situation: undefined } : o);
|
|
530
847
|
const parts = o.parts === true;
|
|
531
848
|
const homeSide = isScore(o) ? resolveHomeSide({ ...o, sport }) : "right";
|
|
532
849
|
const awaySide = homeSide === "left" ? "right" : "left";
|
|
@@ -540,8 +857,8 @@ export function drawKyogijo(o) {
|
|
|
540
857
|
if (isScore(o)) {
|
|
541
858
|
winner = winnerOf({ ...o, sport });
|
|
542
859
|
status = statusText({ ...o, sport }, language);
|
|
543
|
-
const home = teamView(o.home, homeSide, "home", winner, uppercase, sport, o.markShape);
|
|
544
|
-
const away = teamView(o.away, awaySide, "away", winner, uppercase, sport, o.markShape);
|
|
860
|
+
const home = teamView(o.home, homeSide, "home", winner, uppercase, sport, o.markShape, o.theme === "light" || o.theme === "dark" ? o.theme : undefined);
|
|
861
|
+
const away = teamView(o.away, awaySide, "away", winner, uppercase, sport, o.markShape, o.theme === "light" || o.theme === "dark" ? o.theme : undefined);
|
|
545
862
|
left = homeSide === "left" ? home : away;
|
|
546
863
|
right = homeSide === "left" ? away : home;
|
|
547
864
|
leftTeam = homeSide === "left" ? o.home : o.away;
|
|
@@ -555,16 +872,21 @@ export function drawKyogijo(o) {
|
|
|
555
872
|
const featured = featureColours(sport, o.featureColors);
|
|
556
873
|
const features = featured.length === 0 ? undefined : new Set(featured.map(([name]) => name));
|
|
557
874
|
const walled = sport === "mlb" && ballparkDrawn(ballparkFor(o));
|
|
875
|
+
const hardwood = sport === "nba" && o.court?.hardwood !== undefined && o.court.hardwood !== false;
|
|
876
|
+
const crowded = crowdOf(o) !== undefined;
|
|
558
877
|
const style = colourStyle(o, { left: leftTeam, right: rightTeam, home: isScore(o) ? o.home : undefined, away: isScore(o) ? o.away : undefined }, featured);
|
|
559
878
|
const palette = isLook(o.look) ? o.look : undefined;
|
|
879
|
+
const budoLook = isBudoSport(sport) ? budoLookOf(sport, o.budo?.look ?? (sport === "dojo" ? dojoSpecOf(o.dojo).look : undefined)) : undefined;
|
|
560
880
|
let notes;
|
|
561
881
|
const theme = o.theme === "light" || o.theme === "dark" ? o.theme : undefined;
|
|
562
882
|
let viewBox;
|
|
563
883
|
let body;
|
|
564
884
|
let defs = "";
|
|
565
885
|
let grounded = false;
|
|
886
|
+
let foldedSheet = false;
|
|
887
|
+
let pg;
|
|
566
888
|
if (isScore(o) && left !== undefined && right !== undefined && sized === "badge") {
|
|
567
|
-
const badge = badgeMarkup(left, right, { sport, status, parts, id });
|
|
889
|
+
const badge = badgeMarkup(left, right, { sport, status, parts, id, situation: situation === undefined ? undefined : badgeSituation(situation, language) });
|
|
568
890
|
viewBox = `0 0 ${badge.w} ${badge.h}`;
|
|
569
891
|
body = badge.markup;
|
|
570
892
|
}
|
|
@@ -576,13 +898,28 @@ export function drawKyogijo(o) {
|
|
|
576
898
|
const guest = buildSurface({ ...o, margin: 0 }, false, id, isScore(o) && sized === "full", isScore(o), more);
|
|
577
899
|
return composeSpecial(o, guest, (host, hostId) => buildSurface(host, false, hostId, false, false, { features: undefined }), id);
|
|
578
900
|
};
|
|
579
|
-
let surface = make({ features });
|
|
901
|
+
let surface = make({ features, pageant: pageant !== undefined });
|
|
902
|
+
// The score of a pageant with no emblem and no board: the plate stays in the middle if the pictures lose little to it, else it goes to the strip and the surface is built again.
|
|
903
|
+
if (pageant !== undefined && pageant.score === "auto") {
|
|
904
|
+
let score = stripped ? "strip" : "centre";
|
|
905
|
+
if (!stripped && isScore(o) && left !== undefined && right !== undefined && leftTeam !== undefined && rightTeam !== undefined && sized === "full") {
|
|
906
|
+
const [first, second] = pageantPair(surface, { left, right, leftTeam, rightTeam });
|
|
907
|
+
score = autoScore({ pageant, surface, outline: outlineOf(o), left: first, right: second, turned: surface.turned, sport, plate: true });
|
|
908
|
+
}
|
|
909
|
+
pageant = { ...pageant, score };
|
|
910
|
+
if (score === "strip") {
|
|
911
|
+
sized = "compact";
|
|
912
|
+
surface = make({ features, pageant: true });
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
foldedSheet = surface.folded === true;
|
|
580
916
|
// A range too small to hold the score's panel: the score goes to the strip under the drawing, as a compact card does.
|
|
581
917
|
if (surface.plateFits === false) {
|
|
582
918
|
sized = "compact";
|
|
583
|
-
surface = buildSurface(o, portrait, id, false, true, { features });
|
|
919
|
+
surface = buildSurface(o, portrait, id, false, true, { features, pageant: pageant !== undefined });
|
|
584
920
|
}
|
|
585
|
-
|
|
921
|
+
// A folded sheet has no margin for the annotations to stand in: they are not drawn on it.
|
|
922
|
+
if (annotated(o) && o.host === undefined && surface.folded !== true) {
|
|
586
923
|
const teams = { home: isScore(o) ? o.home.name : undefined, away: isScore(o) ? o.away.name : undefined };
|
|
587
924
|
notes = annotate({ o, surface, turned: surface.turned, words: KYOGIJO_STRINGS[language], teams });
|
|
588
925
|
// The annotations need room in the margin: unless the options fix it, the surface is drawn again with a margin that holds them.
|
|
@@ -590,7 +927,7 @@ export function drawKyogijo(o) {
|
|
|
590
927
|
const have = surface.ground ?? (surface.box === undefined ? 0 : surface.box.y - wideView(surface).y);
|
|
591
928
|
const roomed = surface.room ?? have;
|
|
592
929
|
if (o.margin === undefined && (notes.need > have + 0.01 || notes.need > roomed + 0.01)) {
|
|
593
|
-
surface = make({ features, margin: notes.need > have + 0.01 ? notes.need : undefined, room: notes.need });
|
|
930
|
+
surface = make({ features, pageant: pageant !== undefined, margin: notes.need > have + 0.01 ? notes.need : undefined, room: notes.need });
|
|
594
931
|
notes = annotate({ o, surface, turned: surface.turned, words: KYOGIJO_STRINGS[language], teams });
|
|
595
932
|
}
|
|
596
933
|
}
|
|
@@ -602,12 +939,35 @@ export function drawKyogijo(o) {
|
|
|
602
939
|
const ground = laidOn(surface.base, o.background, id);
|
|
603
940
|
grounded = ground.base !== surface.base;
|
|
604
941
|
defs = surface.defs + ground.defs;
|
|
605
|
-
|
|
942
|
+
// The situation: a tint under the lines, and the rest over them and the data (cut with the surface when it is cropped).
|
|
943
|
+
const sit = situation === undefined
|
|
944
|
+
? undefined
|
|
945
|
+
: drawSituation(situation, surface, {
|
|
946
|
+
id,
|
|
947
|
+
language,
|
|
948
|
+
homeSide,
|
|
949
|
+
abbrs: left !== undefined && right !== undefined ? { [left.role]: left.abbr, [right.role]: right.abbr } : undefined,
|
|
950
|
+
plate: isScore(o) && sized === "full" && o.plate !== false,
|
|
951
|
+
strip: stripped && sized === "compact",
|
|
952
|
+
});
|
|
953
|
+
const cutSit = (markup) => (markup !== "" && surface.defs.includes(`id="${id}-rg"`) ? el("g", { "clip-path": `url(#${id}-rg)` }, markup) : markup);
|
|
954
|
+
let inner = ground.base + (sit === undefined ? "" : cutSit(sit.under));
|
|
955
|
+
if (sit !== undefined)
|
|
956
|
+
defs += sit.defs;
|
|
606
957
|
let teams = "";
|
|
607
|
-
|
|
958
|
+
// A pageant lays each team's picture over its half, in place of the names painted at the ends.
|
|
959
|
+
if (pageant !== undefined && isScore(o) && left !== undefined && right !== undefined && leftTeam !== undefined && rightTeam !== undefined && (sized === "full" || sized === "compact")) {
|
|
960
|
+
pg = pageantParts(o, surface, pageant, { left, right, leftTeam, rightTeam, sport, id, plate: sized === "full", parts });
|
|
961
|
+
if (pg !== undefined) {
|
|
962
|
+
defs += pg.defs;
|
|
963
|
+
if (sized === "full" && pg.plateScale !== 1)
|
|
964
|
+
surface.plate = { ...surface.plate, w: surface.plate.w * pg.plateScale, h: surface.plate.h * pg.plateScale };
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (isScore(o) && left !== undefined && right !== undefined && sized === "full" && pg === undefined) {
|
|
608
968
|
const onColour = surface.onColour ?? (sport === "nfl" || sport === "cfl" || sport === "ifaf" || sport === "soccer");
|
|
609
969
|
// A curling sheet, the net sports' courts and a cricket ground have no place for the names: the board names the teams.
|
|
610
|
-
if (sport !== "curling" && !
|
|
970
|
+
if (sport !== "curling" && !hasSetsBoard(sport) && sport !== "cricket" && sport !== "judo" && sport !== "karate" && sport !== "kendo" && sport !== "sumo") {
|
|
611
971
|
// Cropped to a range, a team's name is written only where its place is in what is shown.
|
|
612
972
|
if (shows(surface, surface.left))
|
|
613
973
|
teams += bannerMarkup(surface.left, left, { turned: surface.turned, onColour, parts, id });
|
|
@@ -616,20 +976,43 @@ export function drawKyogijo(o) {
|
|
|
616
976
|
}
|
|
617
977
|
}
|
|
618
978
|
// The teams are painted under the lines, unless the surface asks for them over (a panel that must hide them).
|
|
619
|
-
|
|
979
|
+
if (pg !== undefined && pageant !== undefined) {
|
|
980
|
+
// A surface cropped with room for its annotations is clipped to the cut; the pictures are cut with it.
|
|
981
|
+
const cut = surface.defs.includes(`id="${id}-rg"`);
|
|
982
|
+
const laid = cut ? el("g", { "clip-path": `url(#${id}-rg)` }, pg.pictures) : pg.pictures;
|
|
983
|
+
inner += pageant.lines !== "over" ? surface.lines + laid + pg.names + pg.emblem : laid + surface.lines + pg.names + pg.emblem;
|
|
984
|
+
}
|
|
985
|
+
else
|
|
986
|
+
inner += surface.bannersOver === true ? surface.lines + teams : teams + surface.lines;
|
|
987
|
+
// A lineup's players stand over what the situation lights (a runner's base, a drive's arrows), so that none of them is hidden; any other data goes over it.
|
|
988
|
+
if (sit !== undefined && lineupped)
|
|
989
|
+
inner += cutSit(sit.over);
|
|
620
990
|
// Data goes over the markings and under the score's panel.
|
|
621
|
-
const layered = renderLayers(o, o.layers, surface.turned, surface.whole === undefined ? undefined : surface.box);
|
|
991
|
+
const layered = renderLayers(o, o.layers, surface.turned, surface.whole === undefined ? undefined : surface.box, surface.upright);
|
|
622
992
|
inner += surface.frame === undefined || layered.svg === "" ? layered.svg : el("g", { transform: surface.frame }, layered.svg);
|
|
993
|
+
// A surface drawn in parts shows the data again in each enlarged part, with its own ids, hidden from a reader of the drawing (the strip says it). A colour bar sized
|
|
994
|
+
// against the whole sheet falls outside the panels' part of it and is cut away there; one given a `region` inside a panel's part is drawn there, large.
|
|
995
|
+
if (surface.panels !== undefined && layered.svg !== "" && o.layers !== undefined) {
|
|
996
|
+
surface.panels.forEach((panel, i) => {
|
|
997
|
+
const copy = renderLayers({ ...o, id: `${id}-f${i}` }, o.layers, surface.turned);
|
|
998
|
+
if (copy.svg !== "")
|
|
999
|
+
inner += el("g", { class: "ky-fold-data", "aria-hidden": "true", transform: panel.transform, "clip-path": `url(#${panel.clip})` }, copy.svg);
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
623
1002
|
if (layered.summaries.length > 0 && o.description === undefined) {
|
|
624
1003
|
const { colon, gap } = KYOGIJO_STRINGS[language].said;
|
|
625
1004
|
description = `${said}${gap}${KYOGIJO_STRINGS[language].layers.data}${colon}${layered.summaries.join(gap)}`;
|
|
626
1005
|
}
|
|
1006
|
+
if (sit !== undefined && !lineupped)
|
|
1007
|
+
inner += cutSit(sit.over);
|
|
1008
|
+
if (surface.over !== undefined)
|
|
1009
|
+
inner += surface.over;
|
|
627
1010
|
if (notes !== undefined && notes.svg !== "") {
|
|
628
1011
|
inner += notes.svg;
|
|
629
1012
|
if (notes.summaries.length > 0 && o.description === undefined)
|
|
630
1013
|
description = `${description}${KYOGIJO_STRINGS[language].said.gap}${notes.summaries.join(KYOGIJO_STRINGS[language].said.gap)}`;
|
|
631
1014
|
}
|
|
632
|
-
if (isScore(o) && left !== undefined && right !== undefined && sized === "full") {
|
|
1015
|
+
if (isScore(o) && left !== undefined && right !== undefined && sized === "full" && o.plate !== false) {
|
|
633
1016
|
const foot = o.label !== undefined && o.label !== "" ? o.label : [status, o.date].filter((part) => part !== undefined && part !== "").join(" · ");
|
|
634
1017
|
if (sport === "curling") {
|
|
635
1018
|
const board = boardMarkup(surface.plate, left, right, { competition: o.competition, foot: foot === "" ? undefined : foot, total: KYOGIJO_STRINGS[language].said.total }, { turned: surface.turned, parts });
|
|
@@ -640,17 +1023,22 @@ export function drawKyogijo(o) {
|
|
|
640
1023
|
const board = cricketBoardMarkup(surface.plate, left, right, { competition: o.competition, foot: foot === "" ? undefined : foot, innings: words.innings, total: words.total, overs: words.overs }, { parts });
|
|
641
1024
|
inner += el("g", { transform: `translate(${num(surface.plate.cx)} ${num(surface.plate.cy)})${surface.turned ? " rotate(-90)" : ""}` }, board);
|
|
642
1025
|
}
|
|
643
|
-
else if (
|
|
644
|
-
const
|
|
1026
|
+
else if (isBudoSport(sport) && sport !== "kyudo" && sport !== "dojo") {
|
|
1027
|
+
const b = KYOGIJO_STRINGS[language].budo.board;
|
|
1028
|
+
const board = budoBoardMarkup(sport, surface.plate, left, right, { competition: o.competition, foot: foot === "" ? undefined : foot, wazaari: b.wazaari, yuko: b.yuko, shido: b.shido, senshu: b.senshu, chui: b.chui, kimarite: b.kimarite, techniques: b.techniques, kimariteName: (key) => kimariteName(key, language) }, { parts });
|
|
1029
|
+
inner += el("g", { transform: `translate(${num(surface.plate.cx)} ${num(surface.plate.cy)})${surface.turned ? " rotate(-90)" : ""}` }, board);
|
|
1030
|
+
}
|
|
1031
|
+
else if (hasSetsBoard(sport)) {
|
|
1032
|
+
const board = setsBoardMarkup(surface.plate, left, right, { competition: o.competition, foot: foot === "" ? undefined : foot, head: KYOGIJO_STRINGS[language].net[BOARD[sport] === "games" ? "games" : "sets"], points: KYOGIJO_STRINGS[language].net.points }, { parts, least: minSets(sport, chooseLeague(o).league?.id) });
|
|
645
1033
|
inner += el("g", { transform: `translate(${num(surface.plate.cx)} ${num(surface.plate.cy)})${surface.turned ? " rotate(-90)" : ""}` }, board);
|
|
646
1034
|
}
|
|
647
1035
|
else
|
|
648
1036
|
inner += plateMarkup(surface.plate, left, right, { competition: o.competition, foot: foot === "" ? undefined : foot }, { turned: surface.turned, parts, surfaceSport: sport });
|
|
649
1037
|
}
|
|
650
|
-
const group = el("g", { class: "ky-surface-group", transform: surface.turn, part: parts ? "surface" : undefined }, inner);
|
|
1038
|
+
const group = el("g", { class: "ky-surface-group", transform: surface.turn, part: parts ? "surface" : undefined, ...(o.pointer === true ? fieldAttributes({ ...o, sport }) : {}) }, inner);
|
|
651
1039
|
const v = surface.view;
|
|
652
1040
|
if (isScore(o) && left !== undefined && right !== undefined && sized === "compact") {
|
|
653
|
-
const badge = badgeMarkup(left, right, { sport, status, parts, id });
|
|
1041
|
+
const badge = badgeMarkup(left, right, { sport, status, parts, id, situation: situation === undefined ? undefined : badgeSituation(situation, language) });
|
|
654
1042
|
const scale = v.w / badge.w;
|
|
655
1043
|
const gap = badge.h * scale * 0.12;
|
|
656
1044
|
body = group + el("g", { class: "ky-strip", transform: `translate(${num(v.x)} ${num(v.y + v.h + gap)}) scale(${scale.toFixed(4)})` }, badge.markup);
|
|
@@ -671,19 +1059,21 @@ export function drawKyogijo(o) {
|
|
|
671
1059
|
"data-league": o.league === undefined || o.league === "" ? undefined : o.league,
|
|
672
1060
|
"data-range": isScore(o) && sport === "curling" ? undefined : rangeLabel(o),
|
|
673
1061
|
"data-event": o.host !== undefined && typeof o.event === "string" ? safeClass(o.event) : undefined,
|
|
674
|
-
"data-look": look,
|
|
1062
|
+
"data-look": look ?? budoLook,
|
|
675
1063
|
"data-size": sized,
|
|
676
1064
|
"data-orientation": portrait ? "portrait" : "landscape",
|
|
677
1065
|
"data-theme": theme,
|
|
678
1066
|
"data-palette": palette,
|
|
1067
|
+
"data-track": sport === "athletics" ? o.athletics?.track : undefined,
|
|
679
1068
|
"data-winner": isScore(o) ? winner : undefined,
|
|
1069
|
+
"data-pageant": pg === undefined ? undefined : pageant?.style,
|
|
680
1070
|
"data-version": VERSION,
|
|
681
1071
|
width: safeLength(o.width),
|
|
682
1072
|
height: safeLength(o.height),
|
|
683
1073
|
part: parts ? "svg" : undefined,
|
|
684
1074
|
style: style === "" ? undefined : style,
|
|
685
1075
|
}, `<title id="${titleId}">${esc(title)}</title><desc id="${descId}">${esc(description)}</desc>` +
|
|
686
|
-
(o.style === "none" ? "" : `<style>${KYOGIJO_BASE_STYLE}${left?.round === true || right?.round === true ? `\n${KYOGIJO_MARK_STYLE}` : ""}${sport === "curling" ? `\n${KYOGIJO_CURLING_STYLE}` : ""}${plan === undefined ? "" : `\n${courtStyle(plan.sport, plan.look)}`}${fieldsStyle(sport) === "" ? "" : `\n${fieldsStyle(sport)}`}${palette === undefined ? "" : `\n${lookStyle(palette)}`}${walled ? `\n${KYOGIJO_WALLS_STYLE}` : ""}${features === undefined ? "" : `\n${featureStyle(sport, features)}`}${notes === undefined || notes.svg === "" ? "" : `\n${KYOGIJO_NOTE_STYLE}`}${grounded ? `\n${KYOGIJO_BACKGROUND_STYLE}` : ""}${o.host === undefined ? "" : `\n${specialStyle(hostSport(o.host))}`}</style>`) +
|
|
1076
|
+
(o.style === "none" ? "" : `<style>${KYOGIJO_BASE_STYLE}${left?.round === true || right?.round === true || (pg !== undefined && pageant?.style === "stage") || (pg !== undefined && pageant?.emblem?.shape !== "plain" && pageant?.emblem !== undefined) ? `\n${KYOGIJO_MARK_STYLE}` : ""}${pg === undefined ? "" : `\n${KYOGIJO_PAGEANT_STYLE}${pageant?.animate === undefined || pageant.animate === "none" ? "" : `\n${KYOGIJO_PAGEANT_MOTION}`}`}${sport === "curling" ? `\n${KYOGIJO_CURLING_STYLE}` : ""}${foldedSheet ? `\n${KYOGIJO_FOLD_STYLE}` : ""}${isPoolSport(sport) ? `\n${o.pool?.venue !== undefined ? KYOGIJO_POOL_STYLE : poolStyle({ sport, ...commonOf(o.pool ?? {}), race: o.pool?.race !== undefined, section: o.pool?.section !== undefined && o.pool.section !== false })}` : ""}${plan === undefined ? "" : `\n${courtStyle(plan.sport, plan.look)}`}${fieldsStyle(sport) === "" ? "" : `\n${fieldsStyle(sport)}`}${athleticsStyle(sport) === "" ? "" : `\n${athleticsStyle(sport)}`}${skatingStyle(sport) === "" ? "" : `\n${skatingStyle(sport)}`}${budoLook === undefined ? "" : `\n${budoStyle(sport, budoLook)}`}${palette === undefined ? "" : `\n${lookStyle(palette)}`}${athleticsTrackRules(sport, o.athletics?.track) === "" ? "" : `\n${athleticsTrackRules(sport, o.athletics?.track)}`}${walled ? `\n${KYOGIJO_WALLS_STYLE}` : ""}${hardwood ? `\n${KYOGIJO_HARDWOOD_STYLE}` : ""}${features === undefined ? "" : `\n${featureStyle(sport, features)}`}${notes === undefined || notes.svg === "" ? "" : `\n${KYOGIJO_NOTE_STYLE}`}${grounded ? `\n${KYOGIJO_BACKGROUND_STYLE}` : ""}${crowded ? `\n${KYOGIJO_CROWD_STYLE}` : ""}${crowded && sport === "dojo" ? KYOGIJO_BUDO_GALLERY_STYLE : ""}${situation === undefined ? "" : `\n${KYOGIJO_SITUATION_STYLE}`}${o.host === undefined ? "" : `\n${specialStyle(hostSport(o.host))}`}</style>`) +
|
|
687
1077
|
(defs === "" ? "" : `<defs>${defs}</defs>`) +
|
|
688
1078
|
body);
|
|
689
1079
|
return root;
|
|
@@ -703,3 +1093,21 @@ export function drawScore(options) {
|
|
|
703
1093
|
export function drawBadge(options) {
|
|
704
1094
|
return drawKyogijo({ ...options, size: "badge" });
|
|
705
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* The stands round a surface as data: the rings of seats with their outlines, heights and rake, the blocks of visitors and the places left open, in feet in the surface's
|
|
1098
|
+
* wide frame, so that another view (a 3D one) can raise them. `undefined` when the options ask for no crowd (or for a special game, which has none).
|
|
1099
|
+
* @example
|
|
1100
|
+
* ```ts
|
|
1101
|
+
* import { crowdStands } from "@johnmorrisdotca/kyogijo-stadiums";
|
|
1102
|
+
* const stands = crowdStands({ sport: "soccer", crowd: true });
|
|
1103
|
+
* console.log(stands?.rings.map((ring) => ring.id).join(" "), stands?.shape, stands?.stadium);
|
|
1104
|
+
* // lower upper bowl purpose
|
|
1105
|
+
* ```
|
|
1106
|
+
*/
|
|
1107
|
+
export function crowdStands(o) {
|
|
1108
|
+
const crowd = crowdOf(o);
|
|
1109
|
+
if (crowd === undefined)
|
|
1110
|
+
return undefined;
|
|
1111
|
+
const probe = buildWhole({ ...o, margin: 0 }, false, drawingId(o), false, false, { features: undefined });
|
|
1112
|
+
return standsFor(o, probe, crowd);
|
|
1113
|
+
}
|