@johnmorrisdotca/kyogijo-stadiums 0.24.0 → 0.25.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 +12 -0
- package/NOTICE.md +17 -0
- package/README.md +58 -40
- package/dist/crowd.d.ts +51 -2
- package/dist/crowd.draw.d.ts +3 -1
- package/dist/crowd.draw.js +27 -3
- package/dist/crowd.js +17 -9
- package/dist/draw.js +13 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/strings.d.ts +6 -0
- package/dist/strings.js +2 -2
- package/dist/turn.model.js +3 -1
- package/dist/turn.style.js +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/venue.js +7 -4
- package/dist/venue.real.d.ts +16 -0
- package/dist/venue.real.js +103 -0
- package/dist/venues-entry.d.ts +2 -0
- package/dist/venues-entry.js +2 -0
- package/dist/venues.d.ts +153 -0
- package/dist/venues.data.d.ts +2 -0
- package/dist/venues.data.js +74 -0
- package/dist/venues.geo.d.ts +60 -0
- package/dist/venues.geo.js +211 -0
- package/dist/venues.js +213 -0
- package/dist/venues.osm.data.d.ts +4 -0
- package/dist/venues.osm.data.js +363 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ All notable changes to this project are written here. The format follows
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.25.0] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **The real venues** (`crowd: { real: true }`, [the real venues](./docs/venues.md), entry `@johnmorrisdotca/kyogijo-stadiums/venues`): an NHL arena drawn in the outline of its building, as OpenStreetMap maps it, with the rink lying in it and a plausible bowl of the seats, the seating tiers and the roof the sources give. The first step is the eight arenas of the Pacific Division: the Honda Center, the Scotiabank Saddledome, Rogers Place, the Crypto.com Arena, the SAP Center, the Climate Pledge Arena, Rogers Arena and the T-Mobile Arena. An arena with no venue is drawn with the usual stands, as before; so is any other sport, and a drawing with a `league` of its own.
|
|
15
|
+
- **Level one, the building.** The outline is the closed way OpenStreetMap tags with the arena's Wikidata item, read with the Overpass API on 2026-10-20 and simplified to a metre. The drawing is turned so that the rink lies along the page where the building says how it lies, and a small arrow marked N says where north is; the rink's orientation is inferred from the building's main hall (the largest rectangle that fits its outline) for five of the eight, and not known for the three whose building has no direction (drawn east-west with north at the top and no arrow); OpenStreetMap maps the ice in none of them.
|
|
16
|
+
- **Level two, the bowl.** The venue's seats for ice hockey, in its number of tiers, between the first row and the building's wall: each tier's outer edge is placed so that its band holds its share of the seats (a lower bowl of 56 percent, or the share a source gives: two thirds in the Crypto.com Arena), with a walk between the tiers and rows no steeper than 36 degrees, and a bowl that fits holds exactly the venue's seats. A building too small for them gets a steeper bowl (the Rogers Arena's), and `fit` says `tight` where even that is not enough. The 3D view raises the tiers as solid raked planes, and with `venue: { roof: true }` the building's walls and its roof: a lid, or the Saddledome's saddle (high at the two ends of the rink, low at the two sides). A neutral crowd, no visitors' block and no mark of a team or a league; never a seat map.
|
|
17
|
+
- **Facts with their sources.** `VENUES` holds, for each venue, its seats (Wikidata's figure for ice hockey where its item has one, else the English article's), its number of tiers and its kind of roof, each with whether a source says it (`documented`) or it is ours (`plausible`) and what was read, with the article and revision. Wikidata has no tiers and no roof for any of them; the articles say the Saddledome's roof, the Climate Pledge Arena's, and the tiers of three. `planVenue`, `venueBowl`, `venueOrientation`, `bowlInside` and `venueById` are the rest of the entry.
|
|
18
|
+
- **ODbL data kept apart.** What OpenStreetMap gave (outline, height, the axis worked out from it) is ODbL 1.0 data, "(c) OpenStreetMap contributors": it is only in `src/venues.osm.data.ts` and `data-sources/venues/`, offered under the ODbL with the credit `VENUE_ATTRIBUTION`, and the description of a drawing made from it carries the credit. The facts are in `src/venues.data.ts`, CC0 and facts of English Wikipedia articles, and share nothing with it. The raw answers are kept as they were returned, dated (`pnpm venues:fetch` fetches them politely, one request at a time; `pnpm venues` makes the two data files and the table of the docs from them).
|
|
19
|
+
- **The demo's venues page** (`venues.html`): each of the eight in 2D and in 3D, the four viewpoints, the roof and walls, light and dark, English and Japanese, with what the drawing is made from listed under it. **The docs** have [a page](./docs/venues.md) and [a gallery](https://johnmorrisdotca.github.io/kyogijo-stadiums/docs/gallery-venues.html) of the eight.
|
|
20
|
+
- `CrowdOptions.stands: false` draws no seats (of a real venue only its building and the arrow): what the 3D view's floor needs under the stands it raises.
|
|
21
|
+
|
|
10
22
|
## [0.24.0] - 2026-10-20
|
|
11
23
|
|
|
12
24
|
### Added
|
package/NOTICE.md
CHANGED
|
@@ -43,6 +43,8 @@ picture or code of the sources is copied; each source is named here so that the
|
|
|
43
43
|
| `grounds`: the World Cups each ground staged matches of, and where each final was played | The venue section of the English Wikipedia article of each men's and Women's World Cup, at the revision cited below; FIFA's own pages are not used | Facts, CC BY-SA 4.0 articles as above |
|
|
44
44
|
| `grounds`: the Wikidata item and the coordinates of each ground (`wikidata`, `lat`, `lon`) | The item that each cited article is linked to, its coordinates (P625) and its country (P17), read with the Wikidata API and checked against the item's labels by `scripts/check-grounds.mjs` | Wikidata's data is CC0 (https://creativecommons.org/publicdomain/zero/1.0/) |
|
|
45
45
|
| `arenas`: each arena's names, years, city, seats, rink sizes, Wikidata item and coordinates | The infobox and the text of the English Wikipedia article of each arena, at the revision cited below (the names with the years the article dates them, the year it opened, closed and was pulled down, the seats for ice hockey and for basketball, a rink's length and width where the article gives them in a sentence of its own); the name in Japanese from the title of its Japanese article or written for the package; the Wikidata item (CC0) that each article is linked to and its coordinates (P625) | Facts. The articles are CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/); none of their text, tables or images is used |
|
|
46
|
+
| `venues`: the outline of each NHL arena's building, how its rink lies in it and the building's height (`VENUE_OSM`, `src/venues.osm.data.ts`) | OpenStreetMap, through the Overpass API: the closed way tagged with the venue's Wikidata item (and the ice, where it is mapped), read on 2026-10-20, with the raw answers kept in `data-sources/venues/2026-10-20/`; the outline is simplified to a metre, and the way the rink lies is worked out from it (`coreOf`, `src/venues.geo.ts`) | ODbL 1.0, (c) OpenStreetMap contributors (https://www.openstreetmap.org/copyright): a derived database, kept in its own file and offered under the ODbL; a drawing made from it is a produced work and carries the credit (`VENUE_ATTRIBUTION`) |
|
|
47
|
+
| `venues`: each venue's seats for ice hockey, number of seating tiers and kind of roof (`VENUE_DATA`, `src/venues.data.ts`) | The item of Wikidata (the capacity P1083 and the sport it applies to P641) and the English Wikipedia article of each arena, at the revision cited below, in `data-sources/venues/2026-10-20/` as read; the facts are numbers and words of our own, with what was read in a few words | Wikidata's data is CC0; the facts read from the articles are facts, with the articles credited here (CC BY-SA 4.0) |
|
|
46
48
|
| `atlas`: the clubs that played in each park, ground and arena (`tenants`: the club, its Wikidata item, its league, the years) | The occupants (P466) and home venues (P115) Wikidata lists for each place, with the start (P580) and end (P582) times of each statement, and the clubs' labels in English and Japanese, sports (P641) and leagues (P118), read with the Wikidata API and query service by `scripts/fetch-tenants.mjs` into `scripts/tenants.wikidata.json`; and the `tenants` line of the infobox of each place's English Wikipedia article, at the revision that `source.wikipedia` names for each club (155 articles, read on 2026-10-13) | Facts. Wikidata's data is CC0 (https://creativecommons.org/publicdomain/zero/1.0/), and the articles are CC BY-SA 4.0 as above; the names of clubs and the years are facts, no text, table or image of an article is used. Which clubs are tenants, and the league each is filed under, are our reading, in docs/atlas.md ("Tenants") |
|
|
47
49
|
| `parks`: the walls, quirks, backstop, warning track, dugouts and extra points of a ballpark (`walls`, `quirks`, `backstop_ft`, `track_ft`, `dugouts`, `labels`) | The infobox and the text of the same English article of each park, at the same revision as its fence (the Japanese article for the heights of the walls of the parks of Japan): the height of the wall along a stretch of the fence and the seasons it stood, the hill, overhang, poles, bullpens, ivy and basket the text describes with figures, the infobox's backstop distance, the warning track's width, the sides of the dugouts, and the further distances the text gives (Wrigley Field's wells, Sportsman's Park's and Milwaukee County Stadium's markers). The stretch each figure covers and the angle of each extra point are our reading of the article's words | Facts. The articles are CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/); none of their text, tables or images is used |
|
|
48
50
|
| `parks`: the coordinates of each ballpark (`lat`, `lon`) and the years it opened and closed (`opened`, `closed`) | The item's coordinate location (P625), its date of official opening or inception (P1619, P571) and of official closure or dissolution (P3999, P576), read with the Wikidata API by `scripts/fetch-park-coordinates.mjs` and checked by `scripts/check-parks.mjs` (ES CON Field's opening, 2023, is read from its article) | Wikidata's data is CC0 (https://creativecommons.org/publicdomain/zero/1.0/) |
|
|
@@ -405,6 +407,21 @@ The Japanese Wikipedia articles read for the names, with their revisions, are li
|
|
|
405
407
|
| Verdun Auditorium | Q2870805 | Verdun Auditorium, 1372712513 |
|
|
406
408
|
| Rhode Island Auditorium | Q7320897 | Rhode Island Auditorium, 1373848518 |
|
|
407
409
|
|
|
410
|
+
## The venues' sources
|
|
411
|
+
|
|
412
|
+
The eight arenas of the NHL's Pacific Division, read on 2026-10-20 (`pnpm venues:fetch`; the files are in `data-sources/venues/2026-10-20/`: `osm-<arena>.json` as Overpass returned them, `wikidata.json` and `wikipedia.json`). The outline of a building is OpenStreetMap's, ODbL 1.0, (c) OpenStreetMap contributors, and lives in `src/venues.osm.data.ts` alone. The seats, the tiers and the roof are in `src/venues.data.ts`, with what each cites. No seat map of a team, a ticket seller or a venue is read or copied, and no mark of a team or a league is drawn.
|
|
413
|
+
|
|
414
|
+
| Arena | Wikidata item | OpenStreetMap way | English article and revision |
|
|
415
|
+
| --- | --- | --- | --- |
|
|
416
|
+
| Honda Center | Q774138 | way/120623151 | Honda Center, 1380000927 |
|
|
417
|
+
| Scotiabank Saddledome | Q1140083 | way/4397328 | Scotiabank Saddledome, 1377341466 |
|
|
418
|
+
| Rogers Place | Q5339036 | way/448626254 | Rogers Place, 1380110483 |
|
|
419
|
+
| Crypto.com Arena | Q186080 | way/428021739 | Crypto.com Arena, 1380458624 |
|
|
420
|
+
| SAP Center | Q261863 | way/24169210 | SAP Center, 1380804230 |
|
|
421
|
+
| Climate Pledge Arena | Q977529 | way/25123756 | Climate Pledge Arena, 1380851727 |
|
|
422
|
+
| Rogers Arena | Q517318 | way/24705911 | Rogers Arena, 1379918849 |
|
|
423
|
+
| T-Mobile Arena | Q3338973 | way/364489406 | T-Mobile Arena, 1379155307 |
|
|
424
|
+
|
|
408
425
|
## The World Cups' articles
|
|
409
426
|
|
|
410
427
|
The grounds each World Cup used, and where its final was played, were read from the venue section of the tournament's English Wikipedia article at the revision named (32 tournaments), by the same address. FIFA's own pages are not used.
|
package/README.md
CHANGED
|
@@ -72,46 +72,45 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
72
72
|
|
|
73
73
|
## Features
|
|
74
74
|
|
|
75
|
-
- **Forty-three surfaces, to scale.** The NFL, CFL and IFAF fields, the NHL rink, the NBA court,
|
|
75
|
+
- **Forty-three surfaces, to scale.** The NFL, CFL and IFAF fields, the NHL rink, the NBA court, soccer, baseball, curling, twelve net and racket sports, the pools, athletics, skating, seven field sports, the budō, the MMA cage, the rings and the mats. Every figure is cited in [sources](./docs/sources.md). [The surfaces](./docs/surfaces.md).
|
|
76
76
|
- **Each league's rulebook.** `league: "fiba"` draws a court as FIBA marks it: 48 variants, from the WNBA and the IIHF to Little League, softball, rugby league and box lacrosse, each cited. [League variants](./docs/variants.md).
|
|
77
77
|
- **A realistic basketball floor.** `court: { hardwood: true }` draws maple boards that run the length of the court with staggered ends, grain and stained keys, the baskets with soft shadows, and benches. The clean floor stays the default. [Hardwood](./docs/hardwood.md).
|
|
78
|
-
- **The stands and the crowd.** `crowd: true` draws the seating round any surface that has spectators: a bowl, two sides, a horseshoe, courtside rows or a ballpark's grandstands, with the people as seeded heads
|
|
79
|
-
- **Curling, from the rule books.** A sheet from World Curling's and Curling Canada's rules, tall by default, with the board and the hammer in a score, `curlingStones` for
|
|
80
|
-
- **Net, racket and court sports, from their rulebooks.** The ITF's, FIVB's
|
|
78
|
+
- **The stands and the crowd.** `crowd: true` draws the seating round any surface that has spectators: a bowl, two sides, a horseshoe, courtside rows or a ballpark's grandstands, with the people as seeded heads in the home colours and the empty seats showing. `crowd: { real: true }` puts an NHL arena in its building's outline (OpenStreetMap) with a plausible bowl of its seats, tiers and roof: eight so far, never a seat map. [The crowd](./docs/crowd.md), [the real venues](./docs/venues.md).
|
|
79
|
+
- **Curling, from the rule books.** A sheet from World Curling's and Curling Canada's rules, tall by default, with the board and the hammer in a score, `curlingStones` for an end's stones, `show: "folded"` for both houses enlarged. [Curling](./docs/curling.md).
|
|
80
|
+
- **Net, racket and court sports, from their rulebooks.** The ITF's, FIVB's, BWF's, USA Pickleball's and ITTF's courts and table, and padel, squash, racquetball, sepak takraw, teqball, roundnet and netball, each in its look, with a board of sets and games. [Net, racket and court sports](./docs/courts.md).
|
|
81
81
|
- **Swimming, water polo, diving and artistic swimming, from World Aquatics' regulations.** The 50 or 25 m pool with its lanes, ropes, blocks and touch panels; the water polo field; the diving well; the artistic swimming area. [Pools](./docs/pools.md).
|
|
82
82
|
- **Lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, from their rulebooks.** The fields and floors of World Lacrosse, World Rugby, the NRL, the AFL, the GAA, the FIH and the IHF, and a cricket ground. [Field sports](./docs/field-sports.md).
|
|
83
|
-
- **The athletics stadium, from World Athletics' rules.** The 400 m track with its lanes and staggers worked out from the running lines, every race start, hurdles, the steeplechase and
|
|
84
|
-
- **The skating rinks, from the ISU's rules.** The 400 m speed skating track with
|
|
85
|
-
- **The budō, from the federations' rules.** The IJF's and the All Japan Judo Federation's judo areas, the WKF's karate areas, the kendo shiai-jo, the sumo dohyō, the kyūdōjō, and **a dojo builder**:
|
|
83
|
+
- **The athletics stadium, from World Athletics' rules.** The 400 m track with its lanes and staggers worked out from the running lines, every race start, hurdles, the steeplechase and the field events, with lane draws, results and a race replay. [The athletics stadium](./docs/athletics.md).
|
|
84
|
+
- **The skating rinks, from the ISU's rules.** The 400 m speed skating track with each race's lines worked out lane by lane; the short track's oval; the figure skating rink; and results, a race replay and a programme's elements. [The skating rinks](./docs/skating.md).
|
|
85
|
+
- **The budō, from the federations' rules.** The IJF's and the All Japan Judo Federation's judo areas, the WKF's karate areas, the kendo shiai-jo, the sumo dohyō, the kyūdōjō, and **a dojo builder**: tatami laid as real units, with its walls, doors, windows and shrine. Scores are judo's ippon, waza-ari and shido, points and sumo's kimarite. [The budō](./docs/budo.md).
|
|
86
86
|
- **Soccer, to the Laws.** A pitch from Law 1 of the IFAB Laws of the Game of any size, with presets from international to 5-a-side, half pitches, five mowing patterns and four goal styles. [Soccer](./docs/soccer.md).
|
|
87
|
-
- **Every ballpark.** The 30 current MLB parks and 44 that MLB clubs have left, and the 12 home parks of Nippon Professional Baseball with eight other NPB grounds, each with its fence drawn from the distances published for it, as it stood in a season. [Ballparks](./docs/ballparks.md).
|
|
88
|
-
- **Soccer grounds, arenas and an atlas.** 64 soccer grounds at their published sizes, 167 NHL, NBA, WNBA and PWHL arenas (`drawKyogijo({ sport: "nhl", arena: "boston-garden" })`), and
|
|
89
|
-
- **
|
|
90
|
-
- **Special games.** A surface set inside another, to scale: an NHL rink on a ballpark's infield or a football stadium's field or a baseball field laid over a London stadium's pitch. 18 games, each cited. [Special games](./docs/special-games.md).
|
|
87
|
+
- **Every ballpark.** The 30 current MLB parks and 44 that MLB clubs have left, and the 12 home parks of Nippon Professional Baseball with eight other NPB grounds, each with its fence drawn from the distances published for it, as it stood in a season. With the fence's heights and a park's quirks (`walls`, `quirks`), none guessed. [Ballparks](./docs/ballparks.md).
|
|
88
|
+
- **Soccer grounds, arenas and an atlas.** 64 soccer grounds at their published sizes, 167 NHL, NBA, WNBA and PWHL arenas (`drawKyogijo({ sport: "nhl", arena: "boston-garden" })`), and 330 places on a map, found by any of their names. [The grounds](./docs/grounds.md), [the arenas](./docs/arenas.md), [the atlas](./docs/atlas.md), [names](./docs/ballparks.md#names).
|
|
89
|
+
- **Special games.** A surface set inside another, to scale: an NHL rink on a ballpark's infield, a baseball field over a London stadium's pitch. 18 games, each cited. [Special games](./docs/special-games.md).
|
|
91
90
|
- **Surfaces through the years.** `year: 1975` draws a surface as its league's rules marked it that season, each change cited. [Surfaces through the years](./docs/eras.md).
|
|
92
|
-
- **Score mode.** Each team's name and logo on its side (
|
|
91
|
+
- **Score mode.** Each team's name and logo on its side (end zones, ends of the ice, halves of the court, dugouts) and the score large in the middle, with the competition, status and date, and the winner emphasised. [Score and layout](./docs/score.md#round-marks).
|
|
93
92
|
- **The situation of a game.** `situation` draws what is happening: hockey's power play and shootout, baseball's runners and count, football's line of scrimmage, first-down line, red zone and down and distance, with a drive chart. [The situation](./docs/situation.md).
|
|
94
|
-
- **Lineups.** A `lineup` layer places a team's players by position code (`GK`, `CB`, `HK`, `C`) with no coordinates
|
|
95
|
-
- **A pageant.** Each team's flag or crest laid large over its half of the surface: `pageant: "carpet"` (a flag at its own ratio
|
|
96
|
-
- **Trophies, medals, balls and crests, by id.** `useEmblems(renderEmblem)` plugs in the sister package [Dougu Sports](https://johnmorrisdotca.github.io/dougu-sports/)
|
|
93
|
+
- **Lineups.** A `lineup` layer places a team's players by position code (`GK`, `CB`, `HK`, `C`) with no coordinates, from a formation (36, in 13 sports), as a disc or a jersey with the number, the name, a captain's C and a flag. [Lineups](./docs/team-shape.md#lineups).
|
|
94
|
+
- **A pageant.** Each team's flag or crest laid large over its half of the surface: `pageant: "carpet"` (a flag at its own ratio) or `"stage"` (a crest on a round disc), an emblem or a trophy in the centre circle, the score in the middle or in the strip. [The pageant](./docs/pageant.md).
|
|
95
|
+
- **Trophies, medals, balls and crests, by id.** `useEmblems(renderEmblem)` plugs in the sister package [Dougu Sports](https://johnmorrisdotca.github.io/dougu-sports/), and an id goes wherever a logo, a flag or a mark is taken: `logo: "crest:shield"`, `"ball:puck"`. [Emblems](./docs/emblems.md).
|
|
97
96
|
- **Country flags, by code.** `useFlags(render)` plugs in the sister package [Hata](https://github.com/johnmorrisdotca/hata) through a small adapter, and a team's `flag: "CA"` is its flag: round in a round mark, at its own proportions on a banner, a badge or a carpet. [Flags](./docs/flags.md).
|
|
98
|
-
- **Zoom to a part of a surface.** `range: "offensive-zone"` crops a drawing to a rink's zone, a half court, the paint, the red zone, a penalty area, the infield, a
|
|
99
|
-
- **Wide, tall or fit the box.** Every surface lies wide or tall: tall turns it a quarter, keeps every word upright and puts the teams top and bottom
|
|
100
|
-
- **Where a point lies, by the rules, and a click as a place.** `zoneAt("nhl", [69, 22], { frame: "nhl-api" })` names the zone from the surface's own figures
|
|
97
|
+
- **Zoom to a part of a surface.** `range: "offensive-zone"` crops a drawing to a rink's zone, a half court, the paint, the red zone, a penalty area, the infield, a house, or a box of your own. [Display ranges](./docs/ranges.md).
|
|
98
|
+
- **Wide, tall or fit the box.** Every surface lies wide or tall: tall turns it a quarter, keeps every word upright and puts the teams top and bottom; `orientation: "auto"` follows the box.
|
|
99
|
+
- **Where a point lies, by the rules, and a click as a place.** `zoneAt("nhl", [69, 22], { frame: "nhl-api" })` names the zone from the surface's own figures; `clientPointToField` is a pointer's place in any frame. [Zones](./docs/zones.md), [pointing](./docs/pointer.md).
|
|
101
100
|
- **Goals, the strike zone and the stumps, end-on.** A goal mouth for six sports with the shots laid on it, the catcher's view of the strike zone with its pitches numbered, and the wicket from the bowler's end with its zones. [Targets](./docs/targets.md).
|
|
102
101
|
- **Data on the surface.** Points, lines, arrows, text, heat maps, hexagons and density contours over any surface, in its own feet or a provider's frame; ready-made shot and pass charts. [Data layers](./docs/layers.md), [charts](./docs/charts.md).
|
|
103
|
-
- **Small multiples and backgrounds.** `drawGrid` puts many drawings in one SVG with a title, a shared key and a credit line,
|
|
104
|
-
- **Tournament layouts.** Several surfaces laid out
|
|
102
|
+
- **Small multiples and backgrounds.** `drawGrid` puts many drawings in one SVG with a title, a shared key and a credit line, for a card or a phone; `background` lays a pattern or a photograph behind them. [Layouts and backgrounds](./docs/layouts.md).
|
|
103
|
+
- **Tournament layouts.** Several surfaces laid out for one event, to scale, as one SVG: thirteen presets, each with its rule and sources, and a stadium round it. [Tournament layouts](./docs/multi.md).
|
|
105
104
|
- **Judging assignments.** Who judges where. [Judging](./docs/judging.md). **Boards over a surface.** [Boards](./docs/boards.md).
|
|
106
|
-
- **Replay.** Tracking data played on any surface: the players, the ball and its trail, and the passes, shots and goals as they happen, with controls
|
|
107
|
-
- **A 3D view.** Any surface as a floor that turns by mouse, touch, wheel or keys, with four viewpoints (overhead, broadcast, end-on, low corner), and what
|
|
108
|
-
- **Renderers.** The same drawing as plain data (a scene), on a canvas
|
|
109
|
-
- **Units and frames.** Each surface in its rulebook's unit and any other, and 48 coordinate frames (ten soccer providers, the NHL API, NBA stats, NFL tracking, MLBAM and more)
|
|
105
|
+
- **Replay.** Tracking data played on any surface: the players, the ball and its trail, and the passes, shots and goals as they happen, with controls and the keyboard. [Replay](./docs/replay.md).
|
|
106
|
+
- **A 3D view.** Any surface as a floor that turns by mouse, touch, wheel or keys, with four viewpoints (overhead, broadcast, end-on, low corner), and what stands on it at its height (nets, baskets, goals, a cage's mesh) and the venue round it (raked stands, roofs, walls). [The 3D view](./docs/turn.md).
|
|
107
|
+
- **Renderers.** The same drawing as plain data (a scene), on a canvas, in a d3 selection, as an Observable Plot mark, as GeoJSON and as a PNG in Node, each an entry of its own. [Renderers](./docs/renderers.md).
|
|
108
|
+
- **Units and frames.** Each surface in its rulebook's unit and any other, and 48 coordinate frames (ten soccer providers, the NHL API, NBA stats, NFL tracking, MLBAM and more) for a provider's points. [Units](./docs/units.md), [coordinate frames](./docs/frames.md).
|
|
110
109
|
- **A compact badge and a compact card.** One strip for a list, or the surface with that strip under it.
|
|
111
|
-
- **Light and dark**, by the device or the page; every colour a custom property; eight named looks, colours by feature, line widths and dashes,
|
|
110
|
+
- **Light and dark**, by the device or the page; every colour a custom property; eight named looks, colours by feature, line widths and dashes, arrows, axes and labels. [Theming](./docs/theming.md), [annotations](./docs/annotations.md).
|
|
112
111
|
- **Accessible.** Each drawing is an `img` with a title and a description of the surface and the result, in English or Japanese. [Accessibility](./docs/accessibility.md).
|
|
113
112
|
- **Four ways in.** A function that returns SVG text; a helper that draws into a container; a custom element; a frame for pages with no script; a React helper that imports no React.
|
|
114
|
-
- **No dependencies**, no network requests, nothing stored. Text, colours and logo addresses
|
|
113
|
+
- **No dependencies**, no network requests, nothing stored. Text, colours and logo addresses from outside are made safe.
|
|
115
114
|
- **A docs site.** Guides, a search, a gallery that draws every picture from the code beside it, and [how it compares](./docs/compare.md): [the documentation](./docs/README.md).
|
|
116
115
|
|
|
117
116
|
### What's in it
|
|
@@ -123,17 +122,17 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
|
|
|
123
122
|
| `SOCCER_PITCHES`, `SOCCER_PROVIDERS`, `rescale`, `soccerSpec` | The soccer pitches, the data providers' coordinate systems and the map between them. |
|
|
124
123
|
| `GROUNDS`, `groundById` | The 64 soccer grounds, each pitch at its own size. |
|
|
125
124
|
| `EVENTS`, `eventOptions` | The 18 special games: a rink in a ballpark, a court on a carrier's deck. |
|
|
126
|
-
| `./zones`, `./pointer`, `./target` | Where a point lies by a sport's own rules
|
|
127
|
-
| `./geometry`, `./frames`, `./layers`, `./charts`, `./replay` | The dimensions in any unit; the providers' frames; data layers;
|
|
128
|
-
| `./athletics` | The athletics stadium: the plan, the
|
|
129
|
-
| `./budo` | The budō: the
|
|
130
|
-
| `./skating` | The skating rinks: the plan, the
|
|
131
|
-
| `./parks`, `./grounds`, `./arenas`, `./atlas`, `./eras`, `./leagues`, `./events` | The ballparks,
|
|
125
|
+
| `./zones`, `./pointer`, `./target` | Where a point lies by a sport's own rules; a click as a place in a provider's numbers; a goal, the strike zone or the stumps end-on. |
|
|
126
|
+
| `./geometry`, `./frames`, `./layers`, `./charts`, `./replay` | The dimensions in any unit; the providers' frames; data layers; charts; tracking data played on a surface. |
|
|
127
|
+
| `./athletics` | The athletics stadium: the plan, the races and field events, and the lane draw, results, replay and field marks charts. |
|
|
128
|
+
| `./budo` | The budō: the areas, the dohyō, the kyūdōjō, the dojo builder (`dojo`, `drawDojo`), the 82 kimarite and the five halls. |
|
|
129
|
+
| `./skating` | The skating rinks: the plan, the races, and the pairs, starting positions, results, replay and programme charts. |
|
|
130
|
+
| `./parks`, `./grounds`, `./arenas`, `./venues`, `./atlas`, `./eras`, `./leagues`, `./events` | The ballparks, grounds, arenas and real venues, every place, a season's markings, each league's rulebook, the special games. |
|
|
132
131
|
| `./turn` | A surface as a 3D view that turns, with the net, basket, goal or posts standing on it. |
|
|
133
|
-
| `./scene`, `./canvas`, `./d3`, `./plot`, `./geojson`, `./png` | The drawing as data
|
|
134
|
-
| `./multi` | `drawMulti`, `multiFit`: several surfaces laid out for one event
|
|
135
|
-
| `./judging` | `drawJudging`, `judgingBoard`, `mountJudgingBroadcast`, `judgingPrint`: who judges where,
|
|
136
|
-
| `./layouts` | `drawGrid` and `GRID_PRESETS`: small multiples with a title, a
|
|
132
|
+
| `./scene`, `./canvas`, `./d3`, `./plot`, `./geojson`, `./png` | The drawing as data, on a canvas, in d3, as an Observable Plot mark, as GeoJSON, as a PNG (the optional peer `@resvg/resvg-js`). |
|
|
133
|
+
| `./multi` | `drawMulti`, `multiFit`: several surfaces laid out for one event ([docs](./docs/multi.md), [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html)). |
|
|
134
|
+
| `./judging` | `drawJudging`, `judgingBoard`, `mountJudgingBroadcast`, `judgingPrint`: who judges where, on a plan, a board or paper ([docs](./docs/judging.md)). |
|
|
135
|
+
| `./layouts` | `drawGrid` and `GRID_PRESETS`: small multiples with a title, a key and a credit line; backgrounds. |
|
|
137
136
|
| `./mount`, `./react`, `./element`, `./element/define` | Draw into a container; React props; the `<kyogijo-field>` element and its registration. |
|
|
138
137
|
|
|
139
138
|
The full list of entry points is in [entry points](./docs/entry-points.md); every export is in the [API reference](https://johnmorrisdotca.github.io/kyogijo-stadiums/api.html).
|
|
@@ -496,7 +495,7 @@ console.log(svg.includes('viewBox="0 0 1200 675"'), svg.includes("Three ballpark
|
|
|
496
495
|
|
|
497
496
|
### Several surfaces on one floor
|
|
498
497
|
|
|
499
|
-
`drawMulti` lays the package's own surfaces out
|
|
498
|
+
`drawMulti` lays the package's own surfaces out for one large event, to scale, on one floor, with the officials' chairs and boards and places for the event's words (`sample: true` fills them with an invented event; [tournament layouts](./docs/multi.md)). `multiFit` says whether a layout fits a hall, `stadium: true` sets it inside stands, and `mountMultiTurn` turns it in 3D.
|
|
500
499
|
|
|
501
500
|
```ts
|
|
502
501
|
import { drawMulti, multiLayout } from "@johnmorrisdotca/kyogijo-stadiums/multi";
|
|
@@ -541,8 +540,6 @@ console.log(layout.needs.length, layout.needs.width);
|
|
|
541
540
|
<br><em>Without `sample`: the empty places an organiser fills.</em>
|
|
542
541
|
</p>
|
|
543
542
|
|
|
544
|
-
The [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html) turns it in 3D.
|
|
545
|
-
|
|
546
543
|
### Boards over a surface
|
|
547
544
|
|
|
548
545
|
`board` lays a results board, a bout presentation or a medal table, any SVG, over a surface in 2D and 3D, off its middle and never stretched ([boards](./docs/boards.md)).
|
|
@@ -571,6 +568,26 @@ The [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html) turns
|
|
|
571
568
|
<br><em>A medal table in a corner.</em>
|
|
572
569
|
</p>
|
|
573
570
|
|
|
571
|
+
### The real venues
|
|
572
|
+
|
|
573
|
+
`crowd: { real: true }` draws an NHL arena in its building ([the real venues](./docs/venues.md)).
|
|
574
|
+
|
|
575
|
+
<p align="center">
|
|
576
|
+
<picture>
|
|
577
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/venues-honda-desk-dark.webp">
|
|
578
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/venues-honda-desk-light.webp" alt="The Honda Center's rink in its building's outline: two tiers of seats and a north arrow." width="640">
|
|
579
|
+
</picture>
|
|
580
|
+
<br><em>The Honda Center.</em>
|
|
581
|
+
</p>
|
|
582
|
+
|
|
583
|
+
<p align="center">
|
|
584
|
+
<picture>
|
|
585
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/venues-saddledome-3d-desk-dark.webp">
|
|
586
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/venues-saddledome-3d-desk-light.webp" alt="The Saddledome in 3D: two tiers of seats under its roof." width="640">
|
|
587
|
+
</picture>
|
|
588
|
+
<br><em>The Saddledome, in 3D.</em>
|
|
589
|
+
</p>
|
|
590
|
+
|
|
574
591
|
### Who judges where
|
|
575
592
|
|
|
576
593
|
`drawJudging` puts each judo mat's officials by seat in the picture and in a chart ([judging](./docs/judging.md)).
|
|
@@ -780,7 +797,8 @@ English and Japanese: the title, the description and the standard statuses of a
|
|
|
780
797
|
|
|
781
798
|
Not here yet, each welcome as an [issue](https://github.com/johnmorrisdotca/kyogijo-stadiums/issues):
|
|
782
799
|
|
|
783
|
-
- **More surfaces**: the FIBA and college courts, the international rink, rugby pitches,
|
|
800
|
+
- **More surfaces**: the FIBA and college courts, the international rink, rugby pitches, soccer's beach and street formats.
|
|
801
|
+
- **More real venues**: the other divisions' arenas, then the NBA's, NFL's and MLB's, each in its building's outline.
|
|
784
802
|
- **More parks of the past**: the 19th-century grounds, and the parks whose articles give no distances yet (the Kingdome, Joe Robbie Stadium).
|
|
785
803
|
- **More charts on data layers**: a formation chart, a pass sonar chart and a Voronoi chart of their own (the layers exist; see [team shape](./docs/team-shape.md)).
|
|
786
804
|
- **Football in a different standard**: the college and high-school hash marks.
|
package/dist/crowd.d.ts
CHANGED
|
@@ -26,9 +26,9 @@ export type Outline = {
|
|
|
26
26
|
};
|
|
27
27
|
/** A tier of the stands: a band of seats between two outlines. */
|
|
28
28
|
export interface StandRing {
|
|
29
|
-
/** `lower`, `upper`, `courtside`, `grandstand` or `bleachers`, with the tier's number where a ring has parts. */
|
|
29
|
+
/** `lower`, `middle`, `upper`, `courtside`, `grandstand` or `bleachers`, with the tier's number where a ring has parts. */
|
|
30
30
|
id: string;
|
|
31
|
-
tier: "courtside" | "gallery" | "lower" | "upper" | "grandstand" | "bleachers" | "wall";
|
|
31
|
+
tier: "courtside" | "gallery" | "lower" | "middle" | "upper" | "grandstand" | "bleachers" | "wall";
|
|
32
32
|
/** The band is `region` less `hole` (nothing for a polygon that is the band itself). */
|
|
33
33
|
region: Outline;
|
|
34
34
|
/** Further pieces of the band that are apart from `region` (a ballpark's bleachers either side of the batter's eye). */
|
|
@@ -94,6 +94,45 @@ export interface CrowdStands {
|
|
|
94
94
|
seats: number;
|
|
95
95
|
/** The stands are a hall's gallery (a dojo's balcony): a thin band close to the walls, plain seats, a few neutral people and no sides. */
|
|
96
96
|
gallery?: boolean;
|
|
97
|
+
/** The stands are a real venue's (see `src/venues.ts`): the outline of its building, the way north lies on the page and the roof. */
|
|
98
|
+
real?: RealShell;
|
|
99
|
+
}
|
|
100
|
+
/** The room above a real venue's building that the arrow saying where north is takes, in feet, and how far above the building's box the middle of the arrow stands. */
|
|
101
|
+
export declare const NORTH_ROOM = 60;
|
|
102
|
+
export declare const NORTH_AT = 32;
|
|
103
|
+
/** What a real venue adds to the stands round a surface: the building they stand in, in feet in the wide frame, and the roof over them. */
|
|
104
|
+
export interface RealShell {
|
|
105
|
+
/** The outline of the building, a polygon (OpenStreetMap's, turned so that the rink lies along x). */
|
|
106
|
+
footprint: Pt[];
|
|
107
|
+
/** The hall the stands are in: the bowl's outer wall, a rounded rectangle inside the building, and what the 3D view raises walls and a roof on (the building's annexes, which the outline has, are left as ground). */
|
|
108
|
+
hall: Extract<Outline, {
|
|
109
|
+
kind: "rrect";
|
|
110
|
+
}>;
|
|
111
|
+
/** The way north points on the page, in degrees clockwise from the top; absent where the rink's real orientation is not known. */
|
|
112
|
+
north?: number;
|
|
113
|
+
/** `fixed` is a lid; `saddle` a roof that rises at the two ends and falls at the two sides. */
|
|
114
|
+
roof: "fixed" | "saddle";
|
|
115
|
+
/** The height of the roof's lowest edge above the surface, in feet. */
|
|
116
|
+
edge: number;
|
|
117
|
+
}
|
|
118
|
+
/** The stands of a real venue, worked out from its building (`venueBowl`): what `layoutOf` takes in place of a sport's usual tiers. */
|
|
119
|
+
export interface RealBowl {
|
|
120
|
+
rings: StandRing[];
|
|
121
|
+
/** How far the first row stands from the surface's edge at each side, in feet (the bench side has more). */
|
|
122
|
+
off: {
|
|
123
|
+
left: number;
|
|
124
|
+
right: number;
|
|
125
|
+
top: number;
|
|
126
|
+
bottom: number;
|
|
127
|
+
};
|
|
128
|
+
/** The ground the venue needs beyond the surface on each side, in feet: the building's, and room for the arrow that says where north is. */
|
|
129
|
+
reach: {
|
|
130
|
+
left: number;
|
|
131
|
+
right: number;
|
|
132
|
+
top: number;
|
|
133
|
+
bottom: number;
|
|
134
|
+
};
|
|
135
|
+
shell: RealShell;
|
|
97
136
|
}
|
|
98
137
|
/** The crowd options read: every part has its value. */
|
|
99
138
|
export interface Crowd {
|
|
@@ -112,6 +151,10 @@ export interface Crowd {
|
|
|
112
151
|
gaps: boolean;
|
|
113
152
|
roof: boolean;
|
|
114
153
|
wallSeats: boolean | undefined;
|
|
154
|
+
/** The stands of the arena's real venue, where the package has one for the `arena` asked for. */
|
|
155
|
+
real: boolean;
|
|
156
|
+
/** Whether the seats are drawn (a real venue's building is, without them, when this is false). */
|
|
157
|
+
stands: boolean;
|
|
115
158
|
detail: "auto" | "fine" | "plain";
|
|
116
159
|
}
|
|
117
160
|
/** The crowd the options ask for, or `undefined` for none. */
|
|
@@ -130,6 +173,8 @@ export declare function rayAt(o: Outline, cx: number, cy: number, a: number): Pt
|
|
|
130
173
|
export declare function outlinePath(o: Outline, reverse?: boolean): string;
|
|
131
174
|
/** An outline as points, for a view that raises the stands: arcs are cut into steps of about 7.5 degrees. */
|
|
132
175
|
export declare function outlinePoints(o: Outline): Pt[];
|
|
176
|
+
/** The area of an outline, in square feet. */
|
|
177
|
+
export declare const areaOfOutline: (o: Outline) => number;
|
|
133
178
|
/** The seats of a band of the stands: its area at a seat's 2 by 2.3 feet. */
|
|
134
179
|
export declare const seatsIn: (region: Outline, hole: Outline | null) => number;
|
|
135
180
|
/** A point of a rounded rectangle and the outward normal there, by its parameter `u` (any real number, taken modulo 8): the four straight sides are the even whole numbers (the top from left to right, the right from top to bottom and so on round) and the four corners the odd ones. Concentric outlines (the same corners' centres) have the same parameter at the points an aisle joins. */
|
|
@@ -139,6 +184,8 @@ export declare function rrectAt(o: Extract<Outline, {
|
|
|
139
184
|
p: Pt;
|
|
140
185
|
n: Pt;
|
|
141
186
|
};
|
|
187
|
+
/** The aisles of a band as lines from its inner edge to its outer. */
|
|
188
|
+
export declare function aislesOf(region: Outline, hole: Outline | null): [Pt, Pt][];
|
|
142
189
|
/** What the layout needs of the options and the surface. */
|
|
143
190
|
export interface LayoutInput {
|
|
144
191
|
sport: Sport;
|
|
@@ -159,6 +206,8 @@ export interface LayoutInput {
|
|
|
159
206
|
rows?: number;
|
|
160
207
|
aisles?: readonly number[];
|
|
161
208
|
};
|
|
209
|
+
/** A real venue's stands in place of the sport's usual tiers (see `venueBowl`). */
|
|
210
|
+
real?: RealBowl;
|
|
162
211
|
/** The ballpark's fence as points on the field, for a ballpark (see `parkLayout`). */
|
|
163
212
|
fence?: readonly Pt[];
|
|
164
213
|
/** The foul lines' length at the poles and the backstop's distance, for a ballpark. */
|
package/dist/crowd.draw.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Crowd, type CrowdStands } from "./crowd.ts";
|
|
1
|
+
import { type Crowd, type CrowdStands, type RealShell } from "./crowd.ts";
|
|
2
2
|
/** The tiles a crowd needs: the home tile, the home tile of the upper tiers (emptier) and the visitors', and the display tiles. */
|
|
3
3
|
export declare function patterns(id: string, crowd: Crowd, density: number, tifo: {
|
|
4
4
|
home: boolean;
|
|
@@ -12,6 +12,8 @@ export interface DrawInput {
|
|
|
12
12
|
fine: boolean;
|
|
13
13
|
ground: string;
|
|
14
14
|
}
|
|
15
|
+
/** The building of a real venue and, where its rink's orientation is known, a small arrow with an N that says where north lies. The N is a path of three strokes, so that no font is needed. */
|
|
16
|
+
export declare function realMarkup(real: RealShell): string;
|
|
15
17
|
/** The stands and the crowd as markup and the defs it uses. The markup is laid over the ground and under the surface. */
|
|
16
18
|
export declare function drawCrowd(stands: CrowdStands, o: DrawInput): {
|
|
17
19
|
defs: string;
|
package/dist/crowd.draw.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// All of it is patterns, paths and rectangles, which every renderer of the package reads. The tiles are made from a seed with a generator of our own, so the same options give
|
|
4
4
|
// the same crowd. Written for this package; no photograph or other drawing was copied.
|
|
5
5
|
import { el, num } from "./format.js";
|
|
6
|
-
import { generator, outlinePath } from "./crowd.js";
|
|
6
|
+
import { NORTH_AT, generator, outlinePath } from "./crowd.js";
|
|
7
7
|
/** The width and the height of a tile of the crowd, in feet, and the seats' pitch. */
|
|
8
8
|
const TILE = 14.4;
|
|
9
9
|
const PITCH = 2.4;
|
|
@@ -132,11 +132,32 @@ function galleryRows(ring) {
|
|
|
132
132
|
(gaps === "" ? "" : el("path", { class: "ky-bud-gaisle", d: gaps, fill: "none", "stroke-width": 3.4 })));
|
|
133
133
|
}
|
|
134
134
|
const poly = (points) => `M${points.map(([x, y]) => `${Math.round(x)} ${Math.round(y)}`).join("L")}Z`;
|
|
135
|
+
/** The building of a real venue and, where its rink's orientation is known, a small arrow with an N that says where north lies. The N is a path of three strokes, so that no font is needed. */
|
|
136
|
+
export function realMarkup(real) {
|
|
137
|
+
const fp = real.footprint;
|
|
138
|
+
let svg = el("path", { class: "ky-cr-shell", d: `M${fp.map(([x, y]) => `${n1(x)} ${n1(y)}`).join("L")}Z` });
|
|
139
|
+
if (real.north !== undefined) {
|
|
140
|
+
const top = Math.min(...fp.map((p) => p[1]));
|
|
141
|
+
const right = Math.max(...fp.map((p) => p[0]));
|
|
142
|
+
const [cx, cy] = [right - 34, top - NORTH_AT];
|
|
143
|
+
const a = (real.north * Math.PI) / 180;
|
|
144
|
+
const [dx, dy] = [Math.sin(a), -Math.cos(a)];
|
|
145
|
+
const at = (along, across = 0) => `${n1(cx + dx * along - dy * across)} ${n1(cy + dy * along + dx * across)}`;
|
|
146
|
+
svg += el("path", { class: "ky-cr-north", d: `M${at(-13)}L${at(14)}M${at(14)}L${at(6, 4.5)}L${at(6, -4.5)}Z` });
|
|
147
|
+
const [gx, gy] = [cx + dx * 24, cy + dy * 24];
|
|
148
|
+
svg += el("path", { class: "ky-cr-north-n", d: `M${n1(gx - 3.5)} ${n1(gy + 4.5)}V${n1(gy - 4.5)}L${n1(gx + 3.5)} ${n1(gy + 4.5)}V${n1(gy - 4.5)}` });
|
|
149
|
+
}
|
|
150
|
+
return el("g", { class: "ky-cr-real" }, svg);
|
|
151
|
+
}
|
|
135
152
|
/** The stands and the crowd as markup and the defs it uses. The markup is laid over the ground and under the surface. */
|
|
136
153
|
export function drawCrowd(stands, o) {
|
|
137
154
|
const { id, crowd, density, fine } = o;
|
|
138
155
|
const tifo = { home: stands.sectors.some((s) => s.kind === "tifo-home"), away: stands.sectors.some((s) => s.kind === "tifo-away") };
|
|
139
|
-
|
|
156
|
+
// A real venue's building lies under its stands; with `stands: false` it is all there is.
|
|
157
|
+
const building = stands.real === undefined ? "" : realMarkup(stands.real);
|
|
158
|
+
if (!crowd.stands && stands.real !== undefined)
|
|
159
|
+
return { defs: "", markup: el("g", { class: "ky-crowd" }, building), over: "" };
|
|
160
|
+
let body = building;
|
|
140
161
|
// A ballpark's stands stand on a plaza of their own, not on the grass of the foul ground.
|
|
141
162
|
if (stands.sport === "mlb")
|
|
142
163
|
for (const ring of stands.rings)
|
|
@@ -195,7 +216,7 @@ export function drawCrowd(stands, o) {
|
|
|
195
216
|
const [x0, y0, x1, y1] = g.box;
|
|
196
217
|
body += el("rect", { class: `ky-cr-${g.kind}`, x: n1(x0), y: n1(y0), width: n1(x1 - x0), height: n1(y1 - y0), rx: g.kind === "bench" ? 1 : undefined });
|
|
197
218
|
}
|
|
198
|
-
return { defs: (fine && (stands.gallery !== true || density > 0) ? patterns(id, crowd, density, tifo.home || tifo.away ? tifo : undefined, stands.gallery === true) : ""), markup: el("g", { class: "ky-crowd" }, body), over };
|
|
219
|
+
return { defs: (fine && (stands.gallery !== true || density > 0) ? patterns(id, crowd, density, tifo.home || tifo.away ? tifo : undefined, stands.gallery === true || stands.real !== undefined) : ""), markup: el("g", { class: "ky-crowd" }, body), over };
|
|
199
220
|
}
|
|
200
221
|
/** A block of visitors or a card display, a polygon over the band it is in. */
|
|
201
222
|
function sector(s, id, fine, density) {
|
|
@@ -228,6 +249,9 @@ export const KYOGIJO_CROWD_STYLE = `
|
|
|
228
249
|
.kyogijo .ky-cr-bench{fill:#1c2127;fill-opacity:.55}
|
|
229
250
|
.kyogijo .ky-cr-media{fill:#1c2127;fill-opacity:.4}
|
|
230
251
|
.kyogijo .ky-cr-camera{fill:#1c2127;fill-opacity:.75}
|
|
252
|
+
.kyogijo .ky-cr-shell{fill:var(--ky-cr-conc);fill-opacity:.55;stroke:var(--ky-cr-rim);stroke-width:1.6;stroke-linejoin:round}
|
|
253
|
+
.kyogijo .ky-cr-north{fill:var(--ky-cr-rim);stroke:var(--ky-cr-rim);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
|
|
254
|
+
.kyogijo .ky-cr-north-n{fill:none;stroke:var(--ky-cr-rim);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
|
|
231
255
|
.kyogijo .ky-cr-plaza{fill:var(--ky-apron);stroke:var(--ky-apron);stroke-width:8;stroke-linejoin:round}
|
|
232
256
|
.kyogijo .ky-cr-ez{fill:var(--ky-line);fill-opacity:.16}
|
|
233
257
|
.kyogijo .ky-cr-yard{stroke:var(--ky-line);stroke-opacity:.5;fill:none}`.trim();
|
package/dist/crowd.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// profile of the distances a venue of its kind keeps between the surface and its first row and how deep its tiers are; they are conventions for a drawing, not a rulebook's
|
|
4
4
|
// figures (no rulebook gives them), except the footprint of the gridiron a soccer pitch can stand inside, which is the field's own.
|
|
5
5
|
import { FOOTBALL } from "./geometry.js";
|
|
6
|
+
/** The room above a real venue's building that the arrow saying where north is takes, in feet, and how far above the building's box the middle of the arrow stands. */
|
|
7
|
+
export const NORTH_ROOM = 60;
|
|
8
|
+
export const NORTH_AT = 32;
|
|
6
9
|
const finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
7
10
|
const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
8
11
|
/** The crowd the options ask for, or `undefined` for none. */
|
|
@@ -28,6 +31,8 @@ export function resolveCrowd(value) {
|
|
|
28
31
|
gaps: o.gaps !== false,
|
|
29
32
|
roof: o.roof !== false,
|
|
30
33
|
wallSeats: typeof o.wallSeats === "boolean" ? o.wallSeats : undefined,
|
|
34
|
+
real: o.real === true,
|
|
35
|
+
stands: o.stands !== false,
|
|
31
36
|
detail: o.detail === "fine" || o.detail === "plain" ? o.detail : "auto",
|
|
32
37
|
};
|
|
33
38
|
}
|
|
@@ -216,7 +221,8 @@ export function outlinePoints(o) {
|
|
|
216
221
|
}
|
|
217
222
|
return out;
|
|
218
223
|
}
|
|
219
|
-
|
|
224
|
+
/** The area of an outline, in square feet. */
|
|
225
|
+
export const areaOfOutline = (o) => {
|
|
220
226
|
if (o.kind === "ellipse")
|
|
221
227
|
return Math.PI * o.rx * o.ry;
|
|
222
228
|
if (o.kind === "rrect") {
|
|
@@ -231,7 +237,7 @@ const area = (o) => {
|
|
|
231
237
|
return Math.abs(s) / 2;
|
|
232
238
|
};
|
|
233
239
|
/** The seats of a band of the stands: its area at a seat's 2 by 2.3 feet. */
|
|
234
|
-
export const seatsIn = (region, hole) => Math.round((
|
|
240
|
+
export const seatsIn = (region, hole) => Math.round((areaOfOutline(region) - (hole === null ? 0 : areaOfOutline(hole))) / 4.6);
|
|
235
241
|
/** A point of a rounded rectangle and the outward normal there, by its parameter `u` (any real number, taken modulo 8): the four straight sides are the even whole numbers (the top from left to right, the right from top to bottom and so on round) and the four corners the odd ones. Concentric outlines (the same corners' centres) have the same parameter at the points an aisle joins. */
|
|
236
242
|
export function rrectAt(o, u) {
|
|
237
243
|
const m = ((u % 8) + 8) % 8;
|
|
@@ -281,7 +287,7 @@ function aisleParameters(hole) {
|
|
|
281
287
|
return { us, nh, nv };
|
|
282
288
|
}
|
|
283
289
|
/** The aisles of a band as lines from its inner edge to its outer. */
|
|
284
|
-
function aislesOf(region, hole) {
|
|
290
|
+
export function aislesOf(region, hole) {
|
|
285
291
|
if (region.kind === "rrect" && hole !== null && hole.kind === "rrect")
|
|
286
292
|
return aisleParameters(hole).us.map((u) => [rrectAt(hole, u).p, rrectAt(region, u).p]);
|
|
287
293
|
if (region.kind === "ellipse" && hole !== null && hole.kind === "ellipse") {
|
|
@@ -327,13 +333,13 @@ export function layoutOf(input) {
|
|
|
327
333
|
const host = sport === "soccer" ? (crowd.stadium === "nfl" || crowd.stadium === "cfl" ? crowd.stadium : crowd.stadium === "auto" && input.ground !== undefined ? GRIDIRON_GROUNDS[input.ground] : undefined) : undefined;
|
|
328
334
|
const stadium = sport === "soccer" ? host ?? "purpose" : undefined;
|
|
329
335
|
const p = stadium === "nfl" || stadium === "cfl" ? { ...PROFILES[stadium], shape: base.shape, away: base.away } : base;
|
|
330
|
-
const shape = crowd.shape ?? p.shape;
|
|
331
|
-
const off = offsets(base, box, stadium ?? "purpose");
|
|
336
|
+
const shape = input.real !== undefined ? "bowl" : crowd.shape ?? p.shape;
|
|
337
|
+
const off = input.real?.off ?? offsets(base, box, stadium ?? "purpose");
|
|
332
338
|
const cx = box.x + box.w / 2;
|
|
333
339
|
const cy = box.y + box.h / 2;
|
|
334
|
-
const rings = [];
|
|
335
|
-
const reachOf = { left: 0, right: 0, top: 0, bottom: 0 };
|
|
336
|
-
for (const t of p.tiers) {
|
|
340
|
+
const rings = input.real === undefined ? [] : input.real.rings.map((ring) => ({ ...ring }));
|
|
341
|
+
const reachOf = input.real === undefined ? { left: 0, right: 0, top: 0, bottom: 0 } : { ...input.real.reach };
|
|
342
|
+
for (const t of input.real === undefined ? p.tiers : []) {
|
|
337
343
|
const at = (k) => {
|
|
338
344
|
if (base.oval === true)
|
|
339
345
|
return { kind: "ellipse", cx, cy, rx: box.w / 2 + (off.left + off.right) / 2 + k, ry: box.h / 2 + (off.top + off.bottom) / 2 + k };
|
|
@@ -384,6 +390,8 @@ export function layoutOf(input) {
|
|
|
384
390
|
concourses.push({ region: ring.hole, hole: before.region });
|
|
385
391
|
});
|
|
386
392
|
const stands = { sport, shape, box, rings, covers, concourses, sectors: [], gaps: [], reach: reachOf, seats: rings.reduce((n, r) => n + r.seats, 0) };
|
|
393
|
+
if (input.real !== undefined)
|
|
394
|
+
stands.real = input.real.shell;
|
|
387
395
|
if (stadium !== undefined)
|
|
388
396
|
stands.stadium = stadium;
|
|
389
397
|
if (gal !== undefined)
|
|
@@ -404,7 +412,7 @@ export function layoutOf(input) {
|
|
|
404
412
|
const side = crowd.awayEnd === "left" || crowd.awayEnd === "right" ? crowd.awayEnd : input.awaySide;
|
|
405
413
|
const sign = side === "right" ? 1 : -1;
|
|
406
414
|
const mode = crowd.awayEnd === "auto" ? (p.away === "end" ? "end" : "corner") : crowd.awayEnd === "corner" ? "corner" : "end";
|
|
407
|
-
const tiers = rings.filter((r) => r.tier === "lower" || r.tier === "upper");
|
|
415
|
+
const tiers = rings.filter((r) => r.tier === "lower" || r.tier === "middle" || r.tier === "upper");
|
|
408
416
|
const hole = lowerRing.hole;
|
|
409
417
|
if (lowerRing.region.kind === "rrect" && hole !== null && hole.kind === "rrect") {
|
|
410
418
|
// Round a rectangle a block is whole sections: it starts and ends on aisles, so that it is a section of the stands and not a wedge.
|
package/dist/draw.js
CHANGED
|
@@ -10,6 +10,7 @@ import { ERA_SPORTS, footballIn, rulesFor, seasonLabel } from "./eras.js";
|
|
|
10
10
|
import { FOOTBALL } from "./geometry.js";
|
|
11
11
|
import { renderLayers } from "./layers.js";
|
|
12
12
|
import { arenaById, arenaCourtIn, arenaNameIn, arenaOfficialName, arenaRinkIn } from "./arenas.js";
|
|
13
|
+
import { venueById, venueBowl } from "./venues.js";
|
|
13
14
|
import { groundById, groundNameIn, groundOfficialName } from "./grounds.js";
|
|
14
15
|
import { BOARD, courtFor, hasSetsBoard, isNetLeague, isNetSport } from "./court.js";
|
|
15
16
|
import { cricketBoardMarkup } from "./cricket.board.js";
|
|
@@ -428,10 +429,16 @@ function standsFor(o, surface, crowd) {
|
|
|
428
429
|
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));
|
|
429
430
|
return parkLayout({ fence: fenceOutline(points), backstop, crowd, seatsOnWalls: walls.map((w) => ({ from: w.from, to: w.to, height: w.height_ft })) });
|
|
430
431
|
}
|
|
432
|
+
// An arena's real venue: the building it stands in and a bowl fitted to it, where the package has one for the arena and no league of the caller's own sets the surface.
|
|
433
|
+
const box = surface.whole ?? surface.box ?? { x: 0, y: 0, w: 100, h: 100 };
|
|
434
|
+
const venue = crowd.real && sport === "nhl" && chooseLeague(o).league === undefined ? venueById(o.arena) : undefined;
|
|
435
|
+
// (No visitors' block: no source says where a real arena puts them.)
|
|
436
|
+
if (venue !== undefined)
|
|
437
|
+
return crowdLayout({ sport, box, crowd: crowd.awayEnd === "auto" ? { ...crowd, awayEnd: "none" } : crowd, awaySide, real: venueBowl(venue, box) });
|
|
431
438
|
// 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.
|
|
432
439
|
const hall = sport === "dojo" ? dojoGallery(o) : undefined;
|
|
433
440
|
const gallery = hall === undefined ? undefined : { offset: hall.offset / 0.3048, depth: hall.depth / 0.3048, height: [hall.height[0] / 0.3048, hall.height[1] / 0.3048], rows: hall.rows, aisles: hall.aisles };
|
|
434
|
-
return crowdLayout({ sport, box
|
|
441
|
+
return crowdLayout({ sport, box, crowd, awaySide, ground: o.ground, arena: o.budo?.hall === "budokan", ...(gallery === undefined ? {} : { gallery }) });
|
|
435
442
|
}
|
|
436
443
|
/** True when the drawing is asked to be small: `detail: "simple"` or a `width` under 480 pixels. */
|
|
437
444
|
const smallDrawing = (o) => {
|
|
@@ -716,7 +723,11 @@ export function describe(o) {
|
|
|
716
723
|
const special = specialText(o, language, surfaceName);
|
|
717
724
|
// 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.
|
|
718
725
|
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))}`;
|
|
719
|
-
|
|
726
|
+
// The stands of a real venue say what they are: a plausible bowl, and how the rink lies in the building.
|
|
727
|
+
const realCrowd = o.crowd === undefined || o.crowd === false ? undefined : resolveCrowd(o.crowd);
|
|
728
|
+
const venue = sport === "nhl" && league === undefined && realCrowd?.real === true ? venueById(o.arena) : undefined;
|
|
729
|
+
const realLine = venue === undefined || arenaName === undefined ? "" : `${gap}${fill(words.said.real, { arena: arenaName, seats: String(venue.seats.hockey), tiers: String(venue.tiers.count) })}${gap}${words.said[venue.osm.axis.basis === "mapped" ? "realMapped" : venue.osm.axis.basis === "building" ? "realBuilding" : "realNone"]}`;
|
|
730
|
+
const parkLine = (parkName === undefined ? `${groundLine}${halfLine}${arenaLine}${realLine}` : `${gap}${fill(words.said.park, { park: parkName })}${officially(parkOfficial)}${ballpark === undefined ? "" : ballparkSentences(ballpark).map((line) => `${gap}${line}`).join("")}`) + (special === undefined ? "" : `${gap}${special.text}`);
|
|
720
731
|
// A drawing of a past season says which: the markings are those of that season.
|
|
721
732
|
const dated = typeof o.year === "number" && Number.isFinite(o.year);
|
|
722
733
|
const eraLine = dated && league !== undefined
|
package/dist/index.d.ts
CHANGED
|
@@ -63,6 +63,8 @@ export { ERA_CURRENT, ERA_SOURCES, ERA_SPORTS, eraChanges, eraRange, eraStates,
|
|
|
63
63
|
export type { EraChange, EraRules, EraRulesOf, EraSource, EraSpan, EraSport, FootballRules, MlbRules, NbaRules, NhlRules } from "./eras.ts";
|
|
64
64
|
export { ARENA_IDS, ARENAS, arenaById, arenaByName, arenaByWikidata, arenaCourtIn, arenaNameIn, arenaOfficialName, arenaRinkIn, arenaSourceUrl, arenasByName } from "./arenas.ts";
|
|
65
65
|
export type { Arena, ArenaCapacity, ArenaData, ArenaName, ArenaSize, ArenaSource } from "./arenas.ts";
|
|
66
|
+
export { VENUE_ATTRIBUTION, VENUE_IDS, VENUES, arenaOfVenue, bowlInside, planVenue, venueBowl, venueById, venueByWikidata, venueOrientation, venueRink, venuesIn } from "./venues.ts";
|
|
67
|
+
export type { RealVenue, RealVenueData, VenueBasis, VenueDivision, VenueOrientation, VenueOsm, VenuePlan, VenueRoof } from "./venues.ts";
|
|
66
68
|
export { GROUND_IDS, GROUNDS, groundById, groundByName, groundByWikidata, groundNameIn, groundOfficialName, groundSourceUrl, groundsByName, groundsHosting } from "./grounds.ts";
|
|
67
69
|
export type { Ground, GroundCompetition, GroundData, GroundName, GroundSource, GroundTournament } from "./grounds.ts";
|
|
68
70
|
export { AFL_GROUNDS, FAMILY_OF, LEAGUES, LEAGUE_SOURCES, VARIANTS, chooseLeague, hasHistory, leagueAt, leagueById, leagueChanges, leagueFigures, leagueIds, leagueSeason, leagueSize } from "./leagues.ts";
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export { PARKS, PARK_IDS, fenceFor, parkById, parkByName, parkByWikidata, parkNa
|
|
|
39
39
|
export { officialName, plainName } from "./names.js";
|
|
40
40
|
export { ERA_CURRENT, ERA_SOURCES, ERA_SPORTS, eraChanges, eraRange, eraStates, footballIn, rulesFor, seasonLabel } from "./eras.js";
|
|
41
41
|
export { ARENA_IDS, ARENAS, arenaById, arenaByName, arenaByWikidata, arenaCourtIn, arenaNameIn, arenaOfficialName, arenaRinkIn, arenaSourceUrl, arenasByName } from "./arenas.js";
|
|
42
|
+
export { VENUE_ATTRIBUTION, VENUE_IDS, VENUES, arenaOfVenue, bowlInside, planVenue, venueBowl, venueById, venueByWikidata, venueOrientation, venueRink, venuesIn } from "./venues.js";
|
|
42
43
|
export { GROUND_IDS, GROUNDS, groundById, groundByName, groundByWikidata, groundNameIn, groundOfficialName, groundSourceUrl, groundsByName, groundsHosting } from "./grounds.js";
|
|
43
44
|
export { AFL_GROUNDS, FAMILY_OF, LEAGUES, LEAGUE_SOURCES, VARIANTS, chooseLeague, hasHistory, leagueAt, leagueById, leagueChanges, leagueFigures, leagueIds, leagueSeason, leagueSize } from "./leagues.js";
|
|
44
45
|
export { SURFACE_UNITS, UNITS, convertLength, isUnit } from "./units.js";
|
package/dist/strings.d.ts
CHANGED
|
@@ -504,6 +504,12 @@ export interface KyogijoWords {
|
|
|
504
504
|
arenaSize: string;
|
|
505
505
|
/** An arena whose rink is said to have been shorter than the NHL's, with no size given: {arena}. */
|
|
506
506
|
arenaUnknown: string;
|
|
507
|
+
/** The stands of an arena's real venue: {seats} seats in {tiers} tiers, fitted inside the outline of {arena}'s building from OpenStreetMap. */
|
|
508
|
+
real: string;
|
|
509
|
+
/** How the rink lies in it: along the building's long axis (an inference), as OpenStreetMap maps the ice, or not known. */
|
|
510
|
+
realBuilding: string;
|
|
511
|
+
realMapped: string;
|
|
512
|
+
realNone: string;
|
|
507
513
|
/** A game decided on penalties: {name}, and the shoot-out score {a}-{b}, winner first. */
|
|
508
514
|
wonPens: string;
|
|
509
515
|
/** The shoot-out, as it is written beside a status: {a} and {b}, in the order of the sides on the drawing. */
|