@johnmorrisdotca/kyogijo-stadiums 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +129 -0
- package/LICENSE +21 -0
- package/NOTICE.md +293 -0
- package/README.md +600 -2
- package/dist/annotate.d.ts +47 -0
- package/dist/annotate.js +349 -0
- package/dist/atlas-entry.d.ts +4 -0
- package/dist/atlas-entry.js +3 -0
- package/dist/atlas.d.ts +131 -0
- package/dist/atlas.js +149 -0
- package/dist/background.d.ts +56 -0
- package/dist/background.js +127 -0
- package/dist/ballpark.d.ts +48 -0
- package/dist/ballpark.js +129 -0
- package/dist/canvas-entry.d.ts +2 -0
- package/dist/canvas-entry.js +2 -0
- package/dist/canvas.d.ts +85 -0
- package/dist/canvas.js +279 -0
- package/dist/charts-entry.d.ts +10 -0
- package/dist/charts-entry.js +8 -0
- package/dist/charts.baseball.d.ts +30 -0
- package/dist/charts.baseball.js +152 -0
- package/dist/charts.curling.d.ts +52 -0
- package/dist/charts.curling.js +196 -0
- package/dist/charts.d.ts +172 -0
- package/dist/charts.js +508 -0
- package/dist/charts.network.d.ts +66 -0
- package/dist/charts.network.js +64 -0
- package/dist/charts.soccer.d.ts +43 -0
- package/dist/charts.soccer.js +191 -0
- package/dist/charts.types.d.ts +396 -0
- package/dist/charts.types.js +1 -0
- package/dist/colour.d.ts +29 -0
- package/dist/colour.js +97 -0
- package/dist/common.d.ts +14 -0
- package/dist/common.js +32 -0
- package/dist/court.d.ts +89 -0
- package/dist/court.js +248 -0
- package/dist/courts.style.d.ts +20 -0
- package/dist/courts.style.js +54 -0
- package/dist/cricket.board.d.ts +18 -0
- package/dist/cricket.board.js +67 -0
- package/dist/curling.board.d.ts +24 -0
- package/dist/curling.board.js +147 -0
- package/dist/d3-entry.d.ts +3 -0
- package/dist/d3-entry.js +2 -0
- package/dist/d3.d.ts +45 -0
- package/dist/d3.js +56 -0
- package/dist/draw.d.ts +52 -0
- package/dist/draw.js +705 -0
- package/dist/element-define.d.ts +2 -0
- package/dist/element-define.js +4 -0
- package/dist/element-entry.d.ts +1 -0
- package/dist/element-entry.js +2 -0
- package/dist/element.d.ts +39 -0
- package/dist/element.js +321 -0
- package/dist/eras-entry.d.ts +2 -0
- package/dist/eras-entry.js +2 -0
- package/dist/eras.d.ts +204 -0
- package/dist/eras.js +396 -0
- package/dist/events-entry.d.ts +3 -0
- package/dist/events-entry.js +3 -0
- package/dist/events.d.ts +54 -0
- package/dist/events.data.d.ts +59 -0
- package/dist/events.data.js +297 -0
- package/dist/events.js +127 -0
- package/dist/features.d.ts +31 -0
- package/dist/features.js +284 -0
- package/dist/field.score.d.ts +5 -0
- package/dist/field.score.js +33 -0
- package/dist/fields/afl.d.ts +11 -0
- package/dist/fields/afl.js +103 -0
- package/dist/fields/cricket.d.ts +9 -0
- package/dist/fields/cricket.js +81 -0
- package/dist/fields/fieldhockey.d.ts +6 -0
- package/dist/fields/fieldhockey.js +81 -0
- package/dist/fields/gaelic.d.ts +10 -0
- package/dist/fields/gaelic.js +86 -0
- package/dist/fields/handball.d.ts +6 -0
- package/dist/fields/handball.js +85 -0
- package/dist/fields/lacrosse.d.ts +17 -0
- package/dist/fields/lacrosse.js +169 -0
- package/dist/fields/rugby.d.ts +10 -0
- package/dist/fields/rugby.js +130 -0
- package/dist/fields.d.ts +12 -0
- package/dist/fields.js +44 -0
- package/dist/fields.kit.d.ts +63 -0
- package/dist/fields.kit.js +108 -0
- package/dist/fields.style.d.ts +4 -0
- package/dist/fields.style.js +19 -0
- package/dist/fields.types.d.ts +155 -0
- package/dist/fields.types.js +1 -0
- package/dist/format.d.ts +10 -0
- package/dist/format.js +28 -0
- package/dist/formations.d.ts +18 -0
- package/dist/formations.js +211 -0
- package/dist/frames-entry.d.ts +8 -0
- package/dist/frames-entry.js +7 -0
- package/dist/frames.d.ts +199 -0
- package/dist/frames.js +271 -0
- package/dist/frames.providers.d.ts +16 -0
- package/dist/frames.providers.js +302 -0
- package/dist/geojson-entry.d.ts +2 -0
- package/dist/geojson-entry.js +2 -0
- package/dist/geojson.d.ts +79 -0
- package/dist/geojson.js +147 -0
- package/dist/geometry-entry.d.ts +7 -0
- package/dist/geometry-entry.js +5 -0
- package/dist/geometry.d.ts +295 -0
- package/dist/geometry.js +361 -0
- package/dist/grounds-entry.d.ts +4 -0
- package/dist/grounds-entry.js +3 -0
- package/dist/grounds.d.ts +134 -0
- package/dist/grounds.data.d.ts +2 -0
- package/dist/grounds.data.js +1849 -0
- package/dist/grounds.js +74 -0
- package/dist/heat.colour.d.ts +37 -0
- package/dist/heat.colour.js +54 -0
- package/dist/heat.d.ts +43 -0
- package/dist/heat.js +614 -0
- package/dist/heat.stats.d.ts +123 -0
- package/dist/heat.stats.js +413 -0
- package/dist/heat.types.d.ts +145 -0
- package/dist/heat.types.js +1 -0
- package/dist/heat.zones.d.ts +54 -0
- package/dist/heat.zones.js +424 -0
- package/dist/homeside.d.ts +16 -0
- package/dist/homeside.js +43 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +29 -0
- package/dist/layers-entry.d.ts +19 -0
- package/dist/layers-entry.js +11 -0
- package/dist/layers.d.ts +41 -0
- package/dist/layers.env.d.ts +72 -0
- package/dist/layers.env.js +79 -0
- package/dist/layers.js +533 -0
- package/dist/layers.marks.d.ts +45 -0
- package/dist/layers.marks.js +168 -0
- package/dist/layers.types.d.ts +226 -0
- package/dist/layers.types.js +1 -0
- package/dist/layout.d.ts +97 -0
- package/dist/layout.js +381 -0
- package/dist/layout.style.d.ts +6 -0
- package/dist/layout.style.js +17 -0
- package/dist/layouts-entry.d.ts +5 -0
- package/dist/layouts-entry.js +4 -0
- package/dist/leagues/aussie.d.ts +57 -0
- package/dist/leagues/aussie.js +36 -0
- package/dist/leagues/baseball.d.ts +58 -0
- package/dist/leagues/baseball.js +171 -0
- package/dist/leagues/basketball.d.ts +67 -0
- package/dist/leagues/basketball.js +128 -0
- package/dist/leagues/courts.d.ts +212 -0
- package/dist/leagues/courts.js +114 -0
- package/dist/leagues/cricket.d.ts +45 -0
- package/dist/leagues/cricket.js +34 -0
- package/dist/leagues/curling.d.ts +64 -0
- package/dist/leagues/curling.js +53 -0
- package/dist/leagues/fieldhockey.d.ts +48 -0
- package/dist/leagues/fieldhockey.js +29 -0
- package/dist/leagues/fields.d.ts +10 -0
- package/dist/leagues/fields.js +6 -0
- package/dist/leagues/football.d.ts +8 -0
- package/dist/leagues/football.js +82 -0
- package/dist/leagues/gaelic.d.ts +50 -0
- package/dist/leagues/gaelic.js +29 -0
- package/dist/leagues/handball.d.ts +45 -0
- package/dist/leagues/handball.js +32 -0
- package/dist/leagues/hockey.d.ts +63 -0
- package/dist/leagues/hockey.js +166 -0
- package/dist/leagues/lacrosse.d.ts +103 -0
- package/dist/leagues/lacrosse.js +175 -0
- package/dist/leagues/rugby.d.ts +59 -0
- package/dist/leagues/rugby.js +72 -0
- package/dist/leagues/sources.d.ts +18 -0
- package/dist/leagues/sources.js +95 -0
- package/dist/leagues/types.d.ts +43 -0
- package/dist/leagues/types.js +5 -0
- package/dist/leagues-entry.d.ts +23 -0
- package/dist/leagues-entry.js +15 -0
- package/dist/leagues.d.ts +172 -0
- package/dist/leagues.js +462 -0
- package/dist/look.d.ts +50 -0
- package/dist/look.js +186 -0
- package/dist/mark.d.ts +35 -0
- package/dist/mark.js +59 -0
- package/dist/mount-entry.d.ts +2 -0
- package/dist/mount-entry.js +2 -0
- package/dist/mount.d.ts +63 -0
- package/dist/mount.js +167 -0
- package/dist/mow.d.ts +36 -0
- package/dist/mow.js +111 -0
- package/dist/names.d.ts +77 -0
- package/dist/names.js +97 -0
- package/dist/outline.d.ts +25 -0
- package/dist/outline.js +112 -0
- package/dist/parks-entry.d.ts +4 -0
- package/dist/parks-entry.js +3 -0
- package/dist/parks.d.ts +200 -0
- package/dist/parks.data.d.ts +2 -0
- package/dist/parks.data.js +4489 -0
- package/dist/parks.js +92 -0
- package/dist/plot-entry.d.ts +2 -0
- package/dist/plot-entry.js +2 -0
- package/dist/plot.d.ts +74 -0
- package/dist/plot.js +68 -0
- package/dist/png-entry.d.ts +2 -0
- package/dist/png-entry.js +2 -0
- package/dist/png.d.ts +26 -0
- package/dist/png.js +46 -0
- package/dist/ranges.d.ts +33 -0
- package/dist/ranges.js +178 -0
- package/dist/ranges.names.d.ts +31 -0
- package/dist/ranges.names.js +65 -0
- package/dist/react-entry.d.ts +2 -0
- package/dist/react-entry.js +2 -0
- package/dist/react.d.ts +53 -0
- package/dist/react.js +58 -0
- package/dist/replay-entry.d.ts +5 -0
- package/dist/replay-entry.js +4 -0
- package/dist/replay.control.d.ts +47 -0
- package/dist/replay.control.js +184 -0
- package/dist/replay.d.ts +170 -0
- package/dist/replay.dom.d.ts +21 -0
- package/dist/replay.dom.js +388 -0
- package/dist/replay.js +579 -0
- package/dist/replay.types.d.ts +152 -0
- package/dist/replay.types.js +1 -0
- package/dist/restyle.d.ts +21 -0
- package/dist/restyle.js +70 -0
- package/dist/road.d.ts +26 -0
- package/dist/road.draw.d.ts +6 -0
- package/dist/road.draw.js +269 -0
- package/dist/road.js +59 -0
- package/dist/road.model.d.ts +63 -0
- package/dist/road.model.js +215 -0
- package/dist/road.style.d.ts +7 -0
- package/dist/road.style.js +26 -0
- package/dist/road.types.d.ts +122 -0
- package/dist/road.types.js +1 -0
- package/dist/scene-entry.d.ts +7 -0
- package/dist/scene-entry.js +5 -0
- package/dist/scene.css.d.ts +44 -0
- package/dist/scene.css.js +296 -0
- package/dist/scene.d.ts +27 -0
- package/dist/scene.fit.d.ts +12 -0
- package/dist/scene.fit.js +18 -0
- package/dist/scene.flat.d.ts +38 -0
- package/dist/scene.flat.js +167 -0
- package/dist/scene.js +420 -0
- package/dist/scene.path.d.ts +40 -0
- package/dist/scene.path.js +357 -0
- package/dist/scene.types.d.ts +172 -0
- package/dist/scene.types.js +1 -0
- package/dist/scene.xml.d.ts +31 -0
- package/dist/scene.xml.js +81 -0
- package/dist/score.d.ts +70 -0
- package/dist/score.js +212 -0
- package/dist/sets.board.d.ts +22 -0
- package/dist/sets.board.js +89 -0
- package/dist/sheet.d.ts +18 -0
- package/dist/sheet.js +38 -0
- package/dist/special.d.ts +44 -0
- package/dist/special.js +204 -0
- package/dist/special.style.d.ts +8 -0
- package/dist/special.style.js +36 -0
- package/dist/strings.d.ts +581 -0
- package/dist/strings.js +411 -0
- package/dist/style.d.ts +35 -0
- package/dist/style.js +177 -0
- package/dist/surfaces/baseball.d.ts +33 -0
- package/dist/surfaces/baseball.js +208 -0
- package/dist/surfaces/baseball.walls.d.ts +16 -0
- package/dist/surfaces/baseball.walls.js +150 -0
- package/dist/surfaces/basketball.d.ts +8 -0
- package/dist/surfaces/basketball.js +199 -0
- package/dist/surfaces/curling.d.ts +23 -0
- package/dist/surfaces/curling.js +128 -0
- package/dist/surfaces/field.d.ts +12 -0
- package/dist/surfaces/field.js +163 -0
- package/dist/surfaces/football.d.ts +12 -0
- package/dist/surfaces/football.js +208 -0
- package/dist/surfaces/hockey.d.ts +10 -0
- package/dist/surfaces/hockey.js +166 -0
- package/dist/surfaces/net.d.ts +7 -0
- package/dist/surfaces/net.js +151 -0
- package/dist/surfaces/soccer-providers.d.ts +124 -0
- package/dist/surfaces/soccer-providers.js +334 -0
- package/dist/surfaces/soccer-spec.d.ts +138 -0
- package/dist/surfaces/soccer-spec.js +175 -0
- package/dist/surfaces/soccer.d.ts +25 -0
- package/dist/surfaces/soccer.js +270 -0
- package/dist/surfaces/surface.d.ts +180 -0
- package/dist/surfaces/surface.js +49 -0
- package/dist/team.common.d.ts +75 -0
- package/dist/team.common.js +97 -0
- package/dist/team.formation.d.ts +24 -0
- package/dist/team.formation.js +121 -0
- package/dist/team.geometry.d.ts +66 -0
- package/dist/team.geometry.js +304 -0
- package/dist/team.layers.d.ts +16 -0
- package/dist/team.layers.js +32 -0
- package/dist/team.motion.d.ts +9 -0
- package/dist/team.motion.js +325 -0
- package/dist/team.network.d.ts +43 -0
- package/dist/team.network.js +215 -0
- package/dist/team.shape.d.ts +12 -0
- package/dist/team.shape.js +217 -0
- package/dist/team.types.d.ts +189 -0
- package/dist/team.types.js +1 -0
- package/dist/text.d.ts +31 -0
- package/dist/text.js +88 -0
- package/dist/themes.d.ts +14 -0
- package/dist/themes.js +24 -0
- package/dist/types.d.ts +565 -0
- package/dist/types.js +1 -0
- package/dist/units.d.ts +45 -0
- package/dist/units.js +90 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/package.json +234 -4
package/dist/style.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { KYOGIJO_BACKGROUND_STYLE } from "./background.js";
|
|
2
|
+
import { KYOGIJO_COURTS_STYLE } from "./courts.style.js";
|
|
3
|
+
import { KYOGIJO_FIELDS_STYLE } from "./fields.style.js";
|
|
4
|
+
import { KYOGIJO_FEATURE_STYLE } from "./features.js";
|
|
5
|
+
import { KYOGIJO_GRID_STYLE } from "./layout.style.js";
|
|
6
|
+
import { KYOGIJO_LOOK_STYLE } from "./look.js";
|
|
7
|
+
import { KYOGIJO_MARK_STYLE } from "./mark.js";
|
|
8
|
+
import { KYOGIJO_ROAD_STYLE } from "./road.style.js";
|
|
9
|
+
import { KYOGIJO_SPECIAL_STYLE } from "./special.style.js";
|
|
10
|
+
/**
|
|
11
|
+
* The drawing's stylesheet, without the heat layers' rules: custom properties for every colour, in light and dark, and the rule of each class. It is
|
|
12
|
+
* written into every drawing (so that one saved as a file stands alone) unless `style: "none"` is passed, and the
|
|
13
|
+
* defaults are in `:where()`, which has no weight, so that a page's own rule always wins.
|
|
14
|
+
*/
|
|
15
|
+
export const KYOGIJO_BASE_STYLE = `
|
|
16
|
+
:where(.kyogijo){--ky-ink:#1f2320;--ky-line:#fff;--ky-halo:rgba(255,255,255,.92);--ky-plate:rgba(18,24,21,.9);--ky-plate-ink:#fff;--ky-left:#2f6db0;--ky-right:#b5452c;--ky-left-ink:#fff;--ky-right-ink:#fff;--ky-apron:#dcd8c9;--ky-surface:#3f8f55;--ky-surface-alt:#3a864f;--ky-zone:#2d6a40;--ky-boards:#c8c1b0;--ky-red:#c8372d;--ky-blue:#2a5db0;--ky-dirt:#c28e5c;--ky-foul:#3a8148;--ky-infield:#58a05d;--ky-crease:#bfd3ec;--ky-key:#c25b3c;--ky-centre:transparent;--ky-post:#f2c230;--ky-pylon:#f26a1b;--ky-layer:#14213d;--ky-layer-home:#1f5fa8;--ky-layer-away:#d9480f;--ky-layer-edge:rgba(255,255,255,.92);--ky-layer-hollow:rgba(255,255,255,.32);--ky-layer-ink:#14213d;--ky-layer-halo:rgba(255,255,255,.9);--ky-font:system-ui,-apple-system,"Segoe UI","Hiragino Sans","Noto Sans JP",sans-serif;display:block;width:100%;height:auto;font-family:var(--ky-font)}
|
|
17
|
+
:where(.kyogijo[data-sport=nhl]){--ky-surface:#eef5fa;--ky-apron:#d3dbe1;--ky-boards:#9aa4ab;--ky-halo:rgba(255,255,255,.92)}
|
|
18
|
+
:where(.kyogijo[data-sport=nba]){--ky-surface:#d9a766;--ky-surface-alt:#cf9c5b;--ky-apron:#c9c3b4;--ky-boards:#a97d46;--ky-baseline:#fff}
|
|
19
|
+
:where(.kyogijo[data-sport=mlb]){--ky-surface:#4f9a55;--ky-surface-alt:#478f4e;--ky-apron:#bdb59f;--ky-boards:#2f4a36}
|
|
20
|
+
:where(.kyogijo[data-sport=soccer]){--ky-surface:#4c9b56;--ky-surface-alt:#438f4d;--ky-apron:#c9d2bd;--ky-court:#3b79ad}
|
|
21
|
+
@media (prefers-color-scheme:dark){:where(html:not([data-theme=light]) .kyogijo:not([data-theme=light])){--ky-ink:#ece8dc;--ky-line:#e9ece6;--ky-plate:rgba(0,0,0,.82);--ky-apron:#1b1f1c;--ky-surface:#2c6a3f;--ky-surface-alt:#296239;--ky-zone:#1f4a2d;--ky-boards:#4d5450;--ky-red:#d4574d;--ky-blue:#5584d4;--ky-dirt:#8a6040;--ky-foul:#275a31;--ky-infield:#367a42;--ky-crease:#8ea9cc;--ky-key:#8a3f2b;--ky-layer:#f1f5f9;--ky-layer-home:#6aa9f0;--ky-layer-away:#f59a5b;--ky-layer-edge:rgba(0,0,0,.6);--ky-layer-hollow:rgba(255,255,255,.18);--ky-layer-ink:#f1f5f9;--ky-layer-halo:rgba(0,0,0,.7)}
|
|
22
|
+
:where(html:not([data-theme=light]) .kyogijo[data-sport=nhl]:not([data-theme=light])){--ky-surface:#a9bccb;--ky-apron:#1a2025;--ky-boards:#4b5156}
|
|
23
|
+
:where(html:not([data-theme=light]) .kyogijo[data-sport=nba]:not([data-theme=light])){--ky-surface:#8f6a3c;--ky-surface-alt:#876234;--ky-apron:#1a1c1b;--ky-boards:#5e4426}
|
|
24
|
+
:where(html:not([data-theme=light]) .kyogijo[data-sport=mlb]:not([data-theme=light])){--ky-surface:#2f6b3a;--ky-surface-alt:#2b6336;--ky-apron:#1b1f1c;--ky-boards:#1c2b20}
|
|
25
|
+
:where(html:not([data-theme=light]) .kyogijo[data-sport=soccer]:not([data-theme=light])){--ky-surface:#2d6c3e;--ky-surface-alt:#276136;--ky-apron:#1b1f1c;--ky-court:#2a5478}}
|
|
26
|
+
:where(html[data-theme=dark] .kyogijo,.kyogijo[data-theme=dark]){--ky-ink:#ece8dc;--ky-line:#e9ece6;--ky-plate:rgba(0,0,0,.82);--ky-apron:#1b1f1c;--ky-surface:#2c6a3f;--ky-surface-alt:#296239;--ky-zone:#1f4a2d;--ky-boards:#4d5450;--ky-red:#d4574d;--ky-blue:#5584d4;--ky-dirt:#8a6040;--ky-foul:#275a31;--ky-infield:#367a42;--ky-crease:#8ea9cc;--ky-key:#8a3f2b;--ky-layer:#f1f5f9;--ky-layer-home:#6aa9f0;--ky-layer-away:#f59a5b;--ky-layer-edge:rgba(0,0,0,.6);--ky-layer-hollow:rgba(255,255,255,.18);--ky-layer-ink:#f1f5f9;--ky-layer-halo:rgba(0,0,0,.7)}
|
|
27
|
+
:where(html[data-theme=dark] .kyogijo[data-sport=nhl],.kyogijo[data-theme=dark][data-sport=nhl]){--ky-surface:#a9bccb;--ky-apron:#1a2025;--ky-boards:#4b5156}
|
|
28
|
+
:where(html[data-theme=dark] .kyogijo[data-sport=nba],.kyogijo[data-theme=dark][data-sport=nba]){--ky-surface:#8f6a3c;--ky-surface-alt:#876234;--ky-apron:#1a1c1b;--ky-boards:#5e4426}
|
|
29
|
+
:where(html[data-theme=dark] .kyogijo[data-sport=mlb],.kyogijo[data-theme=dark][data-sport=mlb]){--ky-surface:#2f6b3a;--ky-surface-alt:#2b6336;--ky-apron:#1b1f1c;--ky-boards:#1c2b20}
|
|
30
|
+
:where(html[data-theme=dark] .kyogijo[data-sport=soccer],.kyogijo[data-theme=dark][data-sport=soccer]){--ky-surface:#2d6c3e;--ky-surface-alt:#276136;--ky-apron:#1b1f1c;--ky-court:#2a5478}
|
|
31
|
+
.kyogijo .ky-apron{fill:var(--ky-apron)}
|
|
32
|
+
.kyogijo .ky-text{fill:var(--ky-ink);font-family:var(--ky-font);font-weight:800;letter-spacing:0;font-variant-numeric:tabular-nums}
|
|
33
|
+
.kyogijo .ky-surface{fill:var(--ky-surface)}
|
|
34
|
+
.kyogijo .ky-stripe{fill:var(--ky-surface-alt)}
|
|
35
|
+
.kyogijo .ky-ring circle{stroke:var(--ky-surface-alt)}
|
|
36
|
+
.kyogijo .ky-zone{fill:var(--ky-zone)}
|
|
37
|
+
.kyogijo .ky-zone-left{fill:var(--ky-left)}
|
|
38
|
+
.kyogijo .ky-zone-right{fill:var(--ky-right)}
|
|
39
|
+
.kyogijo .ky-boards{fill:var(--ky-boards)}
|
|
40
|
+
.kyogijo .ky-line{stroke:var(--ky-line);fill:none}
|
|
41
|
+
.kyogijo .ky-fill-line{fill:var(--ky-line)}
|
|
42
|
+
.kyogijo .ky-band{stroke:var(--ky-line)}
|
|
43
|
+
.kyogijo .ky-num{fill:var(--ky-line);font-family:var(--ky-font);font-weight:700}
|
|
44
|
+
.kyogijo .ky-pitch-futsal .ky-surface{fill:var(--ky-court)}
|
|
45
|
+
.kyogijo .ky-goal{stroke:var(--ky-line);fill:none}
|
|
46
|
+
.kyogijo .ky-goal-net{stroke:var(--ky-line);opacity:.55}
|
|
47
|
+
.kyogijo .ky-goal-strip{fill:var(--ky-line)}
|
|
48
|
+
.kyogijo .ky-flag{fill:var(--ky-pylon)}
|
|
49
|
+
.kyogijo .ky-post{stroke:var(--ky-post)}
|
|
50
|
+
.kyogijo .ky-post-end{fill:var(--ky-post)}
|
|
51
|
+
.kyogijo .ky-pylon{fill:var(--ky-pylon)}
|
|
52
|
+
.kyogijo .ky-red{stroke:var(--ky-red)}
|
|
53
|
+
.kyogijo .ky-red-fill{fill:var(--ky-red)}
|
|
54
|
+
.kyogijo .ky-blue{stroke:var(--ky-blue)}
|
|
55
|
+
.kyogijo .ky-blue-fill{fill:var(--ky-blue)}
|
|
56
|
+
.kyogijo .ky-dash{stroke:var(--ky-surface)}
|
|
57
|
+
.kyogijo .ky-crease{fill:var(--ky-crease);stroke:var(--ky-red)}
|
|
58
|
+
.kyogijo .ky-net{stroke:var(--ky-red)}
|
|
59
|
+
.kyogijo .ky-key{fill:var(--ky-key)}
|
|
60
|
+
.kyogijo .ky-key-left{fill:var(--ky-key-left,var(--ky-key))}
|
|
61
|
+
.kyogijo .ky-key-right{fill:var(--ky-key-right,var(--ky-key))}
|
|
62
|
+
.kyogijo .ky-centre{fill:var(--ky-centre)}
|
|
63
|
+
.kyogijo .ky-board{stroke:var(--ky-line)}
|
|
64
|
+
.kyogijo .ky-rim{stroke:#e8591a}
|
|
65
|
+
.kyogijo .ky-baseline{fill:var(--ky-baseline,var(--ky-line))}
|
|
66
|
+
.kyogijo .ky-foul{fill:var(--ky-foul)}
|
|
67
|
+
.kyogijo .ky-track{fill:none;stroke:var(--ky-dirt)}
|
|
68
|
+
.kyogijo .ky-dirt{fill:var(--ky-dirt)}
|
|
69
|
+
.kyogijo .ky-infield{fill:var(--ky-infield)}
|
|
70
|
+
.kyogijo .ky-fence{stroke:var(--ky-boards);stroke-linejoin:round}
|
|
71
|
+
.kyogijo .ky-ink-left{fill:var(--ky-left-ink)}
|
|
72
|
+
.kyogijo .ky-ink-right{fill:var(--ky-right-ink)}
|
|
73
|
+
.kyogijo .ky-paint-left{fill:var(--ky-left);stroke:var(--ky-halo);stroke-width:.14em;paint-order:stroke;stroke-linejoin:round}
|
|
74
|
+
.kyogijo .ky-paint-right{fill:var(--ky-right);stroke:var(--ky-halo);stroke-width:.14em;paint-order:stroke;stroke-linejoin:round}
|
|
75
|
+
.kyogijo .ky-panel-left,.kyogijo .ky-block-left{fill:var(--ky-left)}
|
|
76
|
+
.kyogijo .ky-panel-right,.kyogijo .ky-block-right{fill:var(--ky-right)}
|
|
77
|
+
.kyogijo .ky-lose{opacity:.78}
|
|
78
|
+
.kyogijo .ky-banner.ky-lose{opacity:1;filter:grayscale(.35) brightness(.92)}
|
|
79
|
+
.kyogijo .ky-score.ky-lose{opacity:.62}
|
|
80
|
+
.kyogijo .ky-plate-bg,.kyogijo .ky-badge-bg{fill:var(--ky-plate)}
|
|
81
|
+
.kyogijo .ky-score{fill:var(--ky-plate-ink)}
|
|
82
|
+
.kyogijo .ky-comp,.kyogijo .ky-foot,.kyogijo .ky-abbr,.kyogijo .ky-dash-text,.kyogijo .ky-badge-status{fill:var(--ky-plate-ink);text-anchor:middle}
|
|
83
|
+
.kyogijo .ky-score{font-weight:800}
|
|
84
|
+
.kyogijo .ky-abbr,.kyogijo .ky-comp,.kyogijo .ky-foot,.kyogijo .ky-badge-status{opacity:.82;font-weight:700}
|
|
85
|
+
.kyogijo .ky-dash-text{opacity:.55;font-weight:600}
|
|
86
|
+
.kyogijo .ky-winbar-left{fill:var(--ky-left)}
|
|
87
|
+
.kyogijo .ky-winbar-right{fill:var(--ky-right)}
|
|
88
|
+
.kyogijo .ky-glyph{stroke:var(--ky-plate-ink);stroke-width:1.4;opacity:.7;stroke-linejoin:round}
|
|
89
|
+
.kyogijo .ky-badge-left .ky-score{fill:var(--ky-left-ink)}
|
|
90
|
+
.kyogijo .ky-badge-right .ky-score{fill:var(--ky-right-ink)}
|
|
91
|
+
.kyogijo .ky-badge-left .ky-name{fill:var(--ky-left-ink)}
|
|
92
|
+
.kyogijo .ky-badge-right .ky-name{fill:var(--ky-right-ink)}
|
|
93
|
+
.kyogijo .ky-pts>*{fill:var(--c,var(--ky-layer));stroke:var(--ky-layer-edge);stroke-width:calc(var(--w,.3)*1px);stroke-linejoin:round}
|
|
94
|
+
.kyogijo .ky-pts>.ky-hol{fill:var(--ky-layer-hollow);stroke:var(--c,var(--ky-layer));stroke-width:calc(var(--w,.3)*2.2px)}
|
|
95
|
+
.kyogijo .ky-h{--c:var(--ky-layer-home)}
|
|
96
|
+
.kyogijo .ky-a{--c:var(--ky-layer-away)}
|
|
97
|
+
.kyogijo .ky-ln{fill:none;stroke:var(--c,var(--ky-layer));stroke-linecap:round;stroke-linejoin:round}
|
|
98
|
+
.kyogijo .ky-ah{fill:var(--c,var(--ky-layer));stroke:none}
|
|
99
|
+
.kyogijo .ky-cm{stroke:none}
|
|
100
|
+
.kyogijo .ky-lt{fill:var(--c,var(--ky-layer-ink));stroke:var(--ky-layer-halo);stroke-width:.18em;paint-order:stroke;stroke-linejoin:round;font-family:var(--ky-font);font-weight:700;font-variant-numeric:tabular-nums}
|
|
101
|
+
.kyogijo .ky-lt.ky-nh{stroke:none}
|
|
102
|
+
`.trim();
|
|
103
|
+
/**
|
|
104
|
+
* The rules of the heat layers (the ground under a heat map, its zones' and bands' outlines and the legend), kept apart so that a drawing
|
|
105
|
+
* without one does not carry them: a drawing that has a heat layer writes them in beside the layer, and `KYOGIJO_STYLE` has them for a page.
|
|
106
|
+
*/
|
|
107
|
+
export const KYOGIJO_HEAT_STYLE = `
|
|
108
|
+
:where(.kyogijo){--ky-heat-ground:rgba(255,255,255,.72)}
|
|
109
|
+
@media (prefers-color-scheme:dark){:where(html:not([data-theme=light]) .kyogijo:not([data-theme=light])){--ky-heat-ground:rgba(14,18,16,.82)}}
|
|
110
|
+
:where(html[data-theme=dark] .kyogijo,.kyogijo[data-theme=dark]){--ky-heat-ground:rgba(14,18,16,.82)}
|
|
111
|
+
.kyogijo .ky-hg{fill:var(--ky-heat-ground)}
|
|
112
|
+
.kyogijo .ky-zn,.kyogijo .ky-cf{stroke:var(--ky-layer-edge);stroke-width:calc(var(--w,.2)*1px);stroke-linejoin:round}
|
|
113
|
+
.kyogijo .ky-cl{fill:none;stroke-width:calc(var(--w,.4)*1px);stroke-linejoin:round}
|
|
114
|
+
.kyogijo .ky-lg-p{fill:var(--ky-plate)}
|
|
115
|
+
.kyogijo .ky-lg-t{fill:var(--ky-plate-ink);font-family:var(--ky-font);font-weight:700}
|
|
116
|
+
.kyogijo .ky-lg-k{stroke:var(--ky-plate-ink);fill:none}`.trim();
|
|
117
|
+
/**
|
|
118
|
+
* The rules of a curling sheet and its board: the ice and the lines, the house in its colours (`--ky-rg-o`, `-m`, `-i` and `-b` for the 12-foot band, the 8-foot,
|
|
119
|
+
* the 4-foot and the button), the hacks, the free guard zone, the pebble, the hammer and the board's grid. Kept apart so that a drawing of another sport does not carry
|
|
120
|
+
* them: a curling drawing writes them in after the base rules, and `KYOGIJO_STYLE` has them for a page.
|
|
121
|
+
*/
|
|
122
|
+
export const KYOGIJO_CURLING_STYLE = `
|
|
123
|
+
:where(.kyogijo[data-sport=curling]){--ky-surface:#eaf3f9;--ky-apron:#cfd8de;--ky-boards:#8d98a0;--ky-line:#23292d;--ky-rg-o:#2a5db0;--ky-rg-m:#fff;--ky-rg-i:#c8372d;--ky-rg-b:#fff;--ky-hog:#c8372d;--ky-hack:#3a4046;--ky-pebble:rgba(110,140,165,.4);--ky-fgz:rgba(42,93,176,.1)}
|
|
124
|
+
@media (prefers-color-scheme:dark){:where(html:not([data-theme=light]) .kyogijo[data-sport=curling]:not([data-theme=light])){--ky-surface:#8fa6b7;--ky-apron:#1a2025;--ky-boards:#4b5156;--ky-line:#11171b;--ky-rg-o:#3f6cc0;--ky-rg-m:#dfe8ef;--ky-rg-i:#c9473e;--ky-rg-b:#dfe8ef;--ky-hog:#c9473e;--ky-hack:#161b1f;--ky-fgz:rgba(20,40,90,.18)}}
|
|
125
|
+
:where(html[data-theme=dark] .kyogijo[data-sport=curling],.kyogijo[data-theme=dark][data-sport=curling]){--ky-surface:#8fa6b7;--ky-apron:#1a2025;--ky-boards:#4b5156;--ky-line:#11171b;--ky-rg-o:#3f6cc0;--ky-rg-m:#dfe8ef;--ky-rg-i:#c9473e;--ky-rg-b:#dfe8ef;--ky-hog:#c9473e;--ky-hack:#161b1f;--ky-fgz:rgba(20,40,90,.18)}
|
|
126
|
+
.kyogijo .ky-rg-o{fill:var(--ky-rg-o)}.kyogijo .ky-rg-m{fill:var(--ky-rg-m)}.kyogijo .ky-rg-i{fill:var(--ky-rg-i)}.kyogijo .ky-rg-b{fill:var(--ky-rg-b)}
|
|
127
|
+
.kyogijo .ky-hog{fill:var(--ky-hog)}.kyogijo .ky-hack{fill:var(--ky-hack)}.kyogijo .ky-fgz{fill:var(--ky-fgz)}.kyogijo pattern circle{fill:var(--ky-pebble)}
|
|
128
|
+
.kyogijo .ky-hammer{fill:var(--ky-plate-ink)}.kyogijo .ky-hammer-in{fill:var(--ky-plate)}.kyogijo .ky-grid{stroke:var(--ky-plate-ink);opacity:.22}
|
|
129
|
+
.kyogijo .ky-badge-hammer-left .ky-hammer{fill:var(--ky-left-ink)}.kyogijo .ky-badge-hammer-left .ky-hammer-in{fill:var(--ky-left)}.kyogijo .ky-badge-hammer-right .ky-hammer{fill:var(--ky-right-ink)}.kyogijo .ky-badge-hammer-right .ky-hammer-in{fill:var(--ky-right)}`.trim();
|
|
130
|
+
/**
|
|
131
|
+
* The rules of a ballpark's walls and quirks (`walls` and `quirks`): the four shades of the wall bands (`--ky-wall-1` to `-4`, from under 10 feet to 30 and over), the hill, the
|
|
132
|
+
* overhang, the ivy, the poles and bullpens, the backstop's bar, the dugouts, the names and the legend. Kept apart so that a drawing without them does not carry them: a drawing
|
|
133
|
+
* that has them writes them in after the base rules, and `KYOGIJO_STYLE` has them for a page.
|
|
134
|
+
*/
|
|
135
|
+
export const KYOGIJO_WALLS_STYLE = `
|
|
136
|
+
:where(.kyogijo){--ky-wall-1:#f2e6c2;--ky-wall-2:#e6bd62;--ky-wall-3:#d9742e;--ky-wall-4:#8e2f1c;--ky-hill:#2a5f35;--ky-ivy:#1c6b2f;--ky-over:#101612;--ky-pen:#d9dce0}
|
|
137
|
+
@media (prefers-color-scheme:dark){:where(html:not([data-theme=light]) .kyogijo:not([data-theme=light])){--ky-wall-1:#e9dcb4;--ky-wall-2:#d9ae55;--ky-wall-3:#cc6a2a;--ky-wall-4:#c24a32;--ky-hill:#68a574;--ky-ivy:#4f9a63}}
|
|
138
|
+
:where(html[data-theme=dark] .kyogijo,.kyogijo[data-theme=dark]){--ky-wall-1:#e9dcb4;--ky-wall-2:#d9ae55;--ky-wall-3:#cc6a2a;--ky-wall-4:#c24a32;--ky-hill:#68a574;--ky-ivy:#4f9a63}
|
|
139
|
+
.kyogijo .ky-wall{stroke:var(--ky-layer-edge);stroke-width:.35;stroke-linejoin:round}
|
|
140
|
+
.kyogijo .ky-wall-1{fill:var(--ky-wall-1)}.kyogijo .ky-wall-2{fill:var(--ky-wall-2)}.kyogijo .ky-wall-3{fill:var(--ky-wall-3)}.kyogijo .ky-wall-4{fill:var(--ky-wall-4)}
|
|
141
|
+
.kyogijo .ky-hill{fill:var(--ky-hill);fill-opacity:.6;stroke:var(--ky-line);stroke-width:.5;stroke-dasharray:2 1.5}
|
|
142
|
+
.kyogijo .ky-overhang{fill:var(--ky-over);fill-opacity:.32;stroke:var(--ky-line);stroke-width:.5;stroke-dasharray:3 2}
|
|
143
|
+
.kyogijo .ky-ivy{fill:none;stroke:var(--ky-ivy);stroke-width:3;stroke-dasharray:2.2 1.3;stroke-linecap:round}
|
|
144
|
+
.kyogijo .ky-basket{fill:none;stroke:var(--ky-line);stroke-width:.9;stroke-dasharray:3 1.6}
|
|
145
|
+
.kyogijo .ky-pole{fill:var(--ky-post);stroke:var(--ky-ink);stroke-width:.5}
|
|
146
|
+
.kyogijo .ky-bullpen{fill:var(--ky-pen);stroke:var(--ky-ink);stroke-width:.5}
|
|
147
|
+
.kyogijo .ky-backstop{fill:none;stroke:var(--ky-line);stroke-width:.8}
|
|
148
|
+
.kyogijo .ky-dugout{fill:var(--ky-plate);stroke:var(--ky-line);stroke-width:.6}
|
|
149
|
+
.kyogijo .ky-dugout-away{fill:none}
|
|
150
|
+
.kyogijo .ky-wl{fill:var(--ky-ink);stroke:var(--ky-halo);stroke-width:.14em;paint-order:stroke;stroke-linejoin:round;font-weight:700}
|
|
151
|
+
.kyogijo .ky-wl-p{fill:var(--ky-plate)}
|
|
152
|
+
.kyogijo .ky-wl-k{fill:var(--ky-plate-ink);font-weight:700}`.trim();
|
|
153
|
+
/**
|
|
154
|
+
* The rules of the team layers (the cells, triangles and hulls, the roses of a sonar, the arrows of a flow field and the marks of a formation), kept apart
|
|
155
|
+
* like the heat layers' so that a drawing without one does not carry them: a drawing that has one writes them in beside the layer, and `KYOGIJO_STYLE` has them for a page.
|
|
156
|
+
*/
|
|
157
|
+
export const KYOGIJO_TEAM_STYLE = `
|
|
158
|
+
.kyogijo .ky-sp{fill:var(--c,var(--ky-layer));fill-opacity:.22;stroke:var(--c,var(--ky-layer));stroke-width:calc(var(--w,.3)*1px);stroke-linejoin:round}
|
|
159
|
+
.kyogijo .ky-sp-e{fill:none;stroke-opacity:.8}
|
|
160
|
+
.kyogijo .ky-ro{fill:var(--c,var(--ky-layer));fill-opacity:.7;stroke:var(--ky-layer-edge);stroke-width:calc(var(--w,.3)*1px);stroke-linejoin:round}
|
|
161
|
+
.kyogijo .ky-ro-r{fill:none;stroke:var(--c,var(--ky-layer));stroke-opacity:.45;stroke-dasharray:calc(var(--w,.3)*3px) calc(var(--w,.3)*3px);stroke-width:calc(var(--w,.3)*1px)}
|
|
162
|
+
.kyogijo .ky-fm>*{fill:var(--c,var(--ky-layer));stroke:var(--ky-layer-edge);stroke-width:calc(var(--w,.3)*1px)}
|
|
163
|
+
.kyogijo .ky-fm>.ky-e{fill:var(--ky-layer-hollow);stroke:var(--c,var(--ky-layer));stroke-width:calc(var(--w,.3)*2.2px)}`.trim();
|
|
164
|
+
/**
|
|
165
|
+
* The rules of the annotations (the arrows of `direction`, the axes of `axes` and the labels and leaders of `landmarks`): words in the ink of the page with an outline in the
|
|
166
|
+
* apron's colour, thin leaders, and the arrows in the home and away colours. A drawing that has an annotation writes them in; `KYOGIJO_STYLE` has them for a page.
|
|
167
|
+
*/
|
|
168
|
+
export const KYOGIJO_NOTE_STYLE = `
|
|
169
|
+
.kyogijo .ky-an-t{fill:var(--ky-ink);stroke:var(--ky-apron);stroke-width:.2em;paint-order:stroke;stroke-linejoin:round}
|
|
170
|
+
.kyogijo .ky-an-l{stroke:var(--ky-ink);stroke-opacity:.75}
|
|
171
|
+
.kyogijo .ky-an-d circle{fill:var(--ky-ink);stroke:var(--ky-apron)}
|
|
172
|
+
.kyogijo .ky-an-h{--c:var(--ky-layer-home)}
|
|
173
|
+
.kyogijo .ky-an-a{--c:var(--ky-layer-away)}
|
|
174
|
+
.kyogijo .ky-an-ar{stroke:var(--c);fill:none}
|
|
175
|
+
.kyogijo .ky-an-hd{fill:var(--c)}`.trim();
|
|
176
|
+
/** Every rule of the package, for a page that draws with `style: "none"` and supplies the stylesheet itself. */
|
|
177
|
+
export const KYOGIJO_STYLE = `${KYOGIJO_BASE_STYLE}\n${KYOGIJO_HEAT_STYLE}\n${KYOGIJO_TEAM_STYLE}\n${KYOGIJO_CURLING_STYLE}\n${KYOGIJO_WALLS_STYLE}\n${KYOGIJO_COURTS_STYLE}\n${KYOGIJO_FIELDS_STYLE}\n${KYOGIJO_LOOK_STYLE}\n${KYOGIJO_FEATURE_STYLE}\n${KYOGIJO_NOTE_STYLE}\n${KYOGIJO_SPECIAL_STYLE}\n${KYOGIJO_BACKGROUND_STYLE}\n${KYOGIJO_GRID_STYLE}\n${KYOGIJO_MARK_STYLE}\n${KYOGIJO_ROAD_STYLE}`;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type MlbRules } from "../eras.ts";
|
|
2
|
+
import { type FencePoint } from "../geometry.ts";
|
|
3
|
+
import { type DiamondSpec } from "../leagues/baseball.ts";
|
|
4
|
+
import { type BuildOptions, type Surface } from "./surface.ts";
|
|
5
|
+
/** The fence as points on the field: u across (negative to the left), v out from the back of home plate. */
|
|
6
|
+
export declare function fenceOutline(points: readonly FencePoint[], step?: number): [number, number][];
|
|
7
|
+
/** Home plate as the rules of a season had it: its outline, its half width and where its middle lies out from home. */
|
|
8
|
+
export interface PlateShape {
|
|
9
|
+
/** An outline as a path in the field's screen coordinates (y is minus the distance out from home), or an empty string for a circle. */
|
|
10
|
+
d: string;
|
|
11
|
+
circle?: {
|
|
12
|
+
cx: number;
|
|
13
|
+
cy: number;
|
|
14
|
+
r: number;
|
|
15
|
+
};
|
|
16
|
+
/** Half the plate's width across the line from home to the pitcher. */
|
|
17
|
+
halfWidth: number;
|
|
18
|
+
/** The distance of the plate's middle from the foul lines' meeting, out towards the pitcher. */
|
|
19
|
+
centre: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Home plate in a season: a round plate, a square, the square turned, or the pentagon, centred on the foul lines' meeting, wholly
|
|
23
|
+
* behind it, or in front of it as now. `grow` draws it larger than life, as the rest of the field's small things are.
|
|
24
|
+
*/
|
|
25
|
+
export declare function plateShape(era: Pick<MlbRules, "plateShape" | "platePlacement">, grow: number, plate?: {
|
|
26
|
+
width: number;
|
|
27
|
+
side: number;
|
|
28
|
+
}): PlateShape;
|
|
29
|
+
/**
|
|
30
|
+
* The baseball field: grass, warning track, infield, bases, lines and the fence of a park, with the markings of a season (today's
|
|
31
|
+
* by default). With a `diamond` (leagues.ts) the field of a league, in feet: Little League's, a softball field.
|
|
32
|
+
*/
|
|
33
|
+
export declare function baseball(points: readonly FencePoint[], o: BuildOptions, era?: MlbRules, diamond?: DiamondSpec): Surface;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { el, num } from "../format.js";
|
|
2
|
+
import { rulesFor } from "../eras.js";
|
|
3
|
+
import { MLB, fenceAt, skinJoin } from "../geometry.js";
|
|
4
|
+
import { MLB_DIAMOND } from "../leagues/baseball.js";
|
|
5
|
+
import { mowPark } from "../mow.js";
|
|
6
|
+
import { ballparkLegend, ballparkOver, ballparkRoom, ballparkUnder } from "./baseball.walls.js";
|
|
7
|
+
import { edges, ft } from "./surface.js";
|
|
8
|
+
const SQ = Math.SQRT1_2;
|
|
9
|
+
/** The round home plate of 1857 to 1867, "one square foot", about 13½ inches across, in feet. */
|
|
10
|
+
const ROUND_PLATE = 13.5 / 12;
|
|
11
|
+
/** The fence as points on the field: u across (negative to the left), v out from the back of home plate. */
|
|
12
|
+
export function fenceOutline(points, step = 1.5) {
|
|
13
|
+
const out = [];
|
|
14
|
+
for (let a = -45; a <= 45 + 1e-9; a += step) {
|
|
15
|
+
const d = fenceAt(points, a);
|
|
16
|
+
const t = (a * Math.PI) / 180;
|
|
17
|
+
out.push([d * Math.sin(t), d * Math.cos(t)]);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Home plate in a season: a round plate, a square, the square turned, or the pentagon, centred on the foul lines' meeting, wholly
|
|
23
|
+
* behind it, or in front of it as now. `grow` draws it larger than life, as the rest of the field's small things are.
|
|
24
|
+
*/
|
|
25
|
+
export function plateShape(era, grow, plate = MLB.plate) {
|
|
26
|
+
const { plateShape: shape, platePlacement: placement } = era;
|
|
27
|
+
const half = shape === "circle" ? (ROUND_PLATE / 2) * grow : shape === "square" ? 0.5 * grow : shape === "diamond" ? (Math.SQRT2 / 2) * grow : plate.side * grow;
|
|
28
|
+
const depth = shape === "pentagon" ? plate.width * grow : shape === "circle" ? 2 * half : shape === "square" ? grow : Math.SQRT2 * grow;
|
|
29
|
+
// Where its back point lies on the line out from home: centred on the meeting of the foul lines, wholly behind it, or in front of it.
|
|
30
|
+
const back = placement === "centred" ? -depth / 2 : placement === "behind" ? -depth : 0;
|
|
31
|
+
const v = (n) => -(back + n);
|
|
32
|
+
const centre = shape === "pentagon" ? back + plate.side * grow : back + depth / 2;
|
|
33
|
+
switch (shape) {
|
|
34
|
+
case "circle":
|
|
35
|
+
return { d: "", circle: { cx: 0, cy: v(half), r: half }, halfWidth: half, centre };
|
|
36
|
+
case "square":
|
|
37
|
+
return { d: `M${num(-half)} ${num(v(0))}H${num(half)}V${num(v(depth))}H${num(-half)}Z`, halfWidth: half, centre };
|
|
38
|
+
case "diamond":
|
|
39
|
+
return { d: `M0 ${num(v(0))}L${num(half)} ${num(v(half))}L0 ${num(v(depth))}L${num(-half)} ${num(v(half))}Z`, halfWidth: half, centre };
|
|
40
|
+
case "pentagon":
|
|
41
|
+
return { d: `M0 ${num(v(0))}L${num(half)} ${num(v(half))}V${num(v(depth))}H${num(-half)}V${num(v(half))}Z`, halfWidth: half, centre };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The baseball field: grass, warning track, infield, bases, lines and the fence of a park, with the markings of a season (today's
|
|
46
|
+
* by default). With a `diamond` (leagues.ts) the field of a league, in feet: Little League's, a softball field.
|
|
47
|
+
*/
|
|
48
|
+
export function baseball(points, o, era, diamond = MLB_DIAMOND) {
|
|
49
|
+
const d = diamond;
|
|
50
|
+
// The Official Baseball Rules have a history (eras.ts); a league's field is as its rulebook has it.
|
|
51
|
+
const rules = era ??
|
|
52
|
+
(d === MLB_DIAMOND
|
|
53
|
+
? rulesFor("mlb").rules
|
|
54
|
+
: {
|
|
55
|
+
baseSize: d.baseSize,
|
|
56
|
+
pitcher: { kind: "plate", distance: d.pitcher, width: d.pitchersPlate.width, depth: d.pitchersPlate.depth },
|
|
57
|
+
battersBox: d.boxes === null ? null : { width: d.boxes.batterWidth, length: d.boxes.batterLength, gap: d.boxes.gap },
|
|
58
|
+
plateShape: "pentagon",
|
|
59
|
+
platePlacement: "front",
|
|
60
|
+
moundHeight: null,
|
|
61
|
+
});
|
|
62
|
+
const outline = fenceOutline(points);
|
|
63
|
+
const us = outline.map(([u]) => u);
|
|
64
|
+
const vs = outline.map(([, v]) => v);
|
|
65
|
+
const umin = Math.min(...us);
|
|
66
|
+
const umax = Math.max(...us);
|
|
67
|
+
const vmax = Math.max(...vs);
|
|
68
|
+
// A park's walls and quirks need room beyond the fence, and its backstop and legend room below home plate.
|
|
69
|
+
const b = o.ballpark;
|
|
70
|
+
const room = b === undefined ? { side: 0, below: 0, legend: 0 } : ballparkRoom(b);
|
|
71
|
+
const m = Math.max(o.margin ?? 14, room.side);
|
|
72
|
+
const backstop = d.backstop;
|
|
73
|
+
const bottom = Math.max(backstop + m, room.below);
|
|
74
|
+
const thin = o.exact ? 1 / 3 : 0.7;
|
|
75
|
+
const full = o.detail === "full";
|
|
76
|
+
// Screen coordinates: x is u, y is -v.
|
|
77
|
+
const pt = ([u, v]) => `${num(u)} ${num(-v)}`;
|
|
78
|
+
const fenceD = `M${outline.map(pt).join("L")}`;
|
|
79
|
+
const fairD = `M0 0L${outline.map(pt).join("L")}Z`;
|
|
80
|
+
const fairId = `${o.id}-fair`;
|
|
81
|
+
const strip = o.portrait && o.score ? 60 : 0;
|
|
82
|
+
const view = { x: umin - m, y: -(vmax + m) - strip, w: umax - umin + 2 * m, h: vmax + m + backstop + m + 2 * strip + (bottom - (backstop + m)) + room.legend };
|
|
83
|
+
let base = el("rect", { class: ft(o, "foul-ground", "ky-foul"), x: view.x, y: view.y, width: view.w, height: view.h });
|
|
84
|
+
base += el("path", { class: ft(o, "outfield", "ky-surface"), d: fairD });
|
|
85
|
+
const clip = `<clipPath id="${fairId}"><path d="${fairD}"/></clipPath>`;
|
|
86
|
+
if (o.stripes && (o.mow === undefined || o.mow === "rings" || o.mow === "circles")) {
|
|
87
|
+
const rings = [];
|
|
88
|
+
for (let r = 90, k = 0; r < vmax + 60; r += 30, k += 1) {
|
|
89
|
+
if (k % 2 === 1)
|
|
90
|
+
rings.push(el("circle", { cx: 0, cy: 0, r: r + 15, "stroke-width": 30 }));
|
|
91
|
+
}
|
|
92
|
+
base += el("g", { class: ft(o, "mowing", "ky-ring"), "clip-path": `url(#${fairId})`, fill: "none" }, rings.join(""));
|
|
93
|
+
}
|
|
94
|
+
else if (o.stripes && o.mow !== "none" && o.mow !== undefined) {
|
|
95
|
+
// Another pattern, cut to the fair ground; `wide` and `narrow` are twice and half the usual 30 feet.
|
|
96
|
+
const mown = mowPark(o.mow, { umin, umax, vmax });
|
|
97
|
+
if (mown.path !== "")
|
|
98
|
+
base += el("path", { class: ft(o, "mowing", "ky-stripe"), d: mown.path, "clip-path": `url(#${fairId})` });
|
|
99
|
+
}
|
|
100
|
+
// The warning track: a band along the fence inside the field.
|
|
101
|
+
base += el("path", { class: ft(o, "warning-track", "ky-track"), d: fenceD, fill: "none", "stroke-width": (b?.track ?? MLB.warningTrack) * 2, "clip-path": `url(#${fairId})` });
|
|
102
|
+
if (b !== undefined)
|
|
103
|
+
base += ballparkUnder(b, points);
|
|
104
|
+
// The infield's dirt, cut by an arc round the pitcher's plate, and its grass.
|
|
105
|
+
const skin = d.skinRadius ?? d.base + 5;
|
|
106
|
+
const ua = skinJoin(d.pitcher, skin) * SQ;
|
|
107
|
+
base += el("path", { class: ft(o, "infield-dirt", "ky-dirt"), d: `M0 0L${num(ua)} ${num(-ua)}A${num(skin)} ${num(skin)} 0 0 0 ${num(-ua)} ${num(-ua)}Z` });
|
|
108
|
+
const centreV = d.base * SQ;
|
|
109
|
+
const half = centreV - 4.5 * Math.SQRT2;
|
|
110
|
+
base += el("path", { class: ft(o, "infield-grass", "ky-infield"), d: `M0 ${num(-(centreV + half))}L${num(half)} ${num(-centreV)}L0 ${num(-(centreV - half))}L${num(-half)} ${num(-centreV)}Z` });
|
|
111
|
+
const cuts = [
|
|
112
|
+
[0, 0, MLB.homeCircleRadius],
|
|
113
|
+
[centreV, centreV, MLB.baseCircleRadius],
|
|
114
|
+
[0, 2 * centreV, MLB.baseCircleRadius],
|
|
115
|
+
[-centreV, centreV, MLB.baseCircleRadius],
|
|
116
|
+
];
|
|
117
|
+
// The mound is the plate's: before 1893 the pitcher stood in a chalked box and the sources give no mound.
|
|
118
|
+
if (rules.pitcher.kind === "plate")
|
|
119
|
+
cuts.push([0, d.moundCentre, d.moundRadius]);
|
|
120
|
+
base += cuts.map(([u, v, r]) => el("circle", { class: ft(o, "infield-dirt", "ky-dirt"), cx: u, cy: -v, r })).join("");
|
|
121
|
+
// Lines: the foul lines, the boxes, the lane, the plates, the bases, the fence.
|
|
122
|
+
const first = outline[0];
|
|
123
|
+
const last = outline[outline.length - 1];
|
|
124
|
+
let lines = el("path", { class: ft(o, "foul-lines", "ky-line"), d: `M0 0L${pt(first)}M0 0L${pt(last)}`, "stroke-width": thin, fill: "none" });
|
|
125
|
+
if (full) {
|
|
126
|
+
// The batter's boxes, from 1874: each beside the plate, centred lengthwise on its middle.
|
|
127
|
+
if (rules.battersBox !== null) {
|
|
128
|
+
const { width: batterWidth, length: batterLength, gap } = rules.battersBox;
|
|
129
|
+
const at = plateShape(rules, 1, d.plate);
|
|
130
|
+
const inner = at.halfWidth + gap;
|
|
131
|
+
const boxes = [-1, 1].map((s) => `M${num(s * inner)} ${num(-(at.centre + batterLength / 2))}h${num(s * batterWidth)}v${batterLength}h${num(-s * batterWidth)}z`).join("");
|
|
132
|
+
lines += el("path", { class: ft(o, "batters-boxes", "ky-line"), d: boxes, "stroke-width": thin * 0.8, fill: "none" });
|
|
133
|
+
}
|
|
134
|
+
if (d.runningLane !== null) {
|
|
135
|
+
const dist = (s) => [s * SQ * d.base, -SQ * d.base];
|
|
136
|
+
const off = 3;
|
|
137
|
+
const a = dist(1);
|
|
138
|
+
const b = [a[0] / 2, a[1] / 2];
|
|
139
|
+
const lane = `M${num(b[0])} ${num(b[1])}l${num(off * SQ)} ${num(off * SQ)}L${num(a[0] + off * SQ)} ${num(a[1] + off * SQ)}L${num(a[0])} ${num(a[1])}`;
|
|
140
|
+
lines += el("path", { class: ft(o, "running-lane", "ky-line"), d: lane, "stroke-width": thin * 0.7, fill: "none" });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Bases and plates are drawn larger than life, as broadcast graphics do, unless exact lines are asked for.
|
|
144
|
+
const grow = o.exact ? 1 : 2.4;
|
|
145
|
+
const plate = plateShape(rules, grow, d.plate);
|
|
146
|
+
lines += plate.circle === undefined ? el("path", { class: ft(o, "home-plate", "ky-fill-line"), d: plate.d }) : el("circle", { class: ft(o, "home-plate", "ky-fill-line"), cx: plate.circle.cx, cy: plate.circle.cy, r: plate.circle.r });
|
|
147
|
+
const pitcher = rules.pitcher;
|
|
148
|
+
if (pitcher.kind === "plate") {
|
|
149
|
+
lines += el("rect", { class: ft(o, "pitchers-plate", "ky-fill-line"), x: -1 * grow, y: -(pitcher.distance + 0.25 * grow), width: 2 * grow, height: 0.5 * grow });
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// A chalked box: its front edge the pitching distance from home, its back edge the depth beyond.
|
|
153
|
+
lines += el("rect", { class: ft(o, "pitchers-plate", "ky-line"), x: -pitcher.width / 2, y: -(pitcher.distance + pitcher.depth), width: pitcher.width, height: pitcher.depth, "stroke-width": thin * 0.8, fill: "none" });
|
|
154
|
+
}
|
|
155
|
+
const h = (rules.baseSize * grow * Math.SQRT2) / 2;
|
|
156
|
+
const bases = [
|
|
157
|
+
[centreV - h, centreV],
|
|
158
|
+
[0, 2 * centreV - h],
|
|
159
|
+
[-centreV + h, centreV],
|
|
160
|
+
];
|
|
161
|
+
lines += bases.map(([u, v]) => el("path", { class: ft(o, "bases", "ky-fill-line"), d: `M${num(u)} ${num(-(v + h))}L${num(u + h)} ${num(-v)}L${num(u)} ${num(-(v - h))}L${num(u - h)} ${num(-v)}Z` })).join("");
|
|
162
|
+
lines += el("path", { class: ft(o, "fence", "ky-fence"), d: fenceD, fill: "none", "stroke-width": 1.6 });
|
|
163
|
+
if (b !== undefined) {
|
|
164
|
+
lines += ballparkOver(b, points);
|
|
165
|
+
if (b.legend)
|
|
166
|
+
lines += ballparkLegend(b, bottom + 3);
|
|
167
|
+
}
|
|
168
|
+
const left = { cx: 0, cy: 0, w: 0, h: 0, rot: 0, panel: true };
|
|
169
|
+
const right = { ...left };
|
|
170
|
+
if (strip > 0) {
|
|
171
|
+
const w = Math.min(view.w * 0.9, 300);
|
|
172
|
+
Object.assign(left, { cx: (umin + umax) / 2, cy: view.y + strip / 2, w, h: strip - 12 });
|
|
173
|
+
Object.assign(right, { cx: (umin + umax) / 2, cy: view.y + view.h - strip / 2, w, h: strip - 12 });
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const w = Math.min(172, -62 - (umin - m + 6));
|
|
177
|
+
const cy = 18;
|
|
178
|
+
Object.assign(left, { cx: (umin - m + 6 + -62) / 2, cy, w, h: 58 });
|
|
179
|
+
Object.assign(right, { cx: (umax + m - 6 + 62) / 2, cy, w, h: 58 });
|
|
180
|
+
}
|
|
181
|
+
const surface = { sport: "mlb", view, base, lines, defs: clip, left, right, plate: { cx: 0, cy: -Math.round(vmax * 0.42), w: 150, h: 62 }, turned: false, lineRef: { width: thin, feet: 1 }, box: { x: umin, y: -vmax, w: umax - umin, h: vmax } };
|
|
182
|
+
// The infield: the dirt out to the arc round the mound, with the ground behind home plate; the outfield: the fence in to just short of second base.
|
|
183
|
+
surface.ranges = {
|
|
184
|
+
infield: edges(-(ua + 15), -(d.pitcher + skin + 12), ua + 15, 0),
|
|
185
|
+
outfield: edges(umin, -vmax, umax, -(2 * centreV - 6)),
|
|
186
|
+
};
|
|
187
|
+
if (o.landmarks === true) {
|
|
188
|
+
const mid = outline[Math.round(outline.length / 2)];
|
|
189
|
+
const aside = outline[Math.round(outline.length * 0.8)];
|
|
190
|
+
const marks = [
|
|
191
|
+
{ id: "home-plate", x: 0, y: 0, side: "bottom" },
|
|
192
|
+
{ id: "first-base", x: bases[0][0], y: -bases[0][1], side: "bottom" },
|
|
193
|
+
{ id: "third-base", x: bases[2][0], y: -bases[2][1], side: "bottom" },
|
|
194
|
+
{ id: "second-base", x: bases[1][0], y: -bases[1][1], side: "top" },
|
|
195
|
+
{ id: "foul-line", x: first[0] * 0.55, y: -first[1] * 0.55, side: "top" },
|
|
196
|
+
{ id: "outfield-fence", x: mid[0], y: -mid[1], side: "top" },
|
|
197
|
+
{ id: "warning-track", x: aside[0] * 0.97, y: -aside[1] * 0.97, side: "top" },
|
|
198
|
+
];
|
|
199
|
+
if (rules.pitcher.kind === "plate")
|
|
200
|
+
marks.push({ id: "pitchers-plate", x: 0, y: -rules.pitcher.distance, side: "bottom" });
|
|
201
|
+
if (rules.battersBox !== null) {
|
|
202
|
+
const at = plateShape(rules, 1, d.plate);
|
|
203
|
+
marks.push({ id: "batters-box", x: at.halfWidth + rules.battersBox.gap + rules.battersBox.width / 2, y: -at.centre, side: "bottom" });
|
|
204
|
+
}
|
|
205
|
+
surface.marks = marks;
|
|
206
|
+
}
|
|
207
|
+
return surface;
|
|
208
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FencePoint } from "../geometry.ts";
|
|
2
|
+
import { type Ballpark } from "../ballpark.ts";
|
|
3
|
+
/** How wide the band of a wall is drawn, in feet, from its height in feet: a taller wall has a wider band. */
|
|
4
|
+
export declare const bandWidth: (feet: number) => number;
|
|
5
|
+
/** The room a ballpark's additions need: beyond the fence at the sides and top, below home plate for the backstop's bar, and under the drawing for the legend. */
|
|
6
|
+
export declare function ballparkRoom(b: Ballpark): {
|
|
7
|
+
side: number;
|
|
8
|
+
below: number;
|
|
9
|
+
legend: number;
|
|
10
|
+
};
|
|
11
|
+
/** What is drawn under the lines: the hill and the overhang on the grass, the bands of the walls outside the fence, and the dugouts. */
|
|
12
|
+
export declare function ballparkUnder(b: Ballpark, points: readonly FencePoint[]): string;
|
|
13
|
+
/** What is drawn over the lines: the ivy and the basket, the poles and the bullpens, the backstop's bar, and the names. */
|
|
14
|
+
export declare function ballparkOver(b: Ballpark, points: readonly FencePoint[]): string;
|
|
15
|
+
/** The key to the shades: a panel with its heading and the four tiers, centred under the field, its top at `y`. */
|
|
16
|
+
export declare function ballparkLegend(b: Ballpark, y: number): string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// The walls and quirks of a ballpark, drawn on its field: a band outside each stretch of the fence whose width and shade say how high it stands, the hill,
|
|
2
|
+
// the overhang, the ivy, the poles and bullpens, the distance to the backstop and the dugouts. The figures are the park's article's (parks.ts); where it gives
|
|
3
|
+
// none nothing is drawn. Everything is in the field's own frame, in feet: x across (negative to the left), y minus the distance out from home plate.
|
|
4
|
+
import { el, num } from "../format.js";
|
|
5
|
+
import { fenceAt } from "../geometry.js";
|
|
6
|
+
import { lengthText, quirkName, tierOf, tierTexts, wallText } from "../ballpark.js";
|
|
7
|
+
import { textOn } from "./surface.js";
|
|
8
|
+
const RAD = Math.PI / 180;
|
|
9
|
+
const SQ = Math.SQRT1_2;
|
|
10
|
+
/** The size of the words on the field and in the legend, in feet. */
|
|
11
|
+
const TEXT = 6.5;
|
|
12
|
+
/** How wide the band of a wall is drawn, in feet, from its height in feet: a taller wall has a wider band. */
|
|
13
|
+
export const bandWidth = (feet) => 2 + 0.22 * feet;
|
|
14
|
+
const at = (angle, distance) => [distance * Math.sin(angle * RAD), -distance * Math.cos(angle * RAD)];
|
|
15
|
+
const pt = ([x, y]) => `${num(x)} ${num(y)}`;
|
|
16
|
+
/** The angles from `from` to `to`, a step of 1.5 degrees apart and ending on `to`. */
|
|
17
|
+
function angles(from, to) {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (let a = from; a < to - 1e-9; a += 1.5)
|
|
20
|
+
out.push(a);
|
|
21
|
+
out.push(to);
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/** A closed shape between two offsets of the fence over a stretch of it: `inner` and `outer` are distances to add to the fence's. */
|
|
25
|
+
function strip(points, from, to, inner, outer) {
|
|
26
|
+
const as = angles(from, to);
|
|
27
|
+
const near = as.map((a) => at(a, fenceAt(points, a) + inner));
|
|
28
|
+
const far = as.map((a) => at(a, fenceAt(points, a) + outer)).reverse();
|
|
29
|
+
return `M${[...near, ...far].map(pt).join("L")}Z`;
|
|
30
|
+
}
|
|
31
|
+
/** An open line along the fence over a stretch of it, offset from it. */
|
|
32
|
+
function along(points, from, to, offset) {
|
|
33
|
+
return `M${angles(from, to).map((a) => pt(at(a, fenceAt(points, a) + offset))).join("L")}`;
|
|
34
|
+
}
|
|
35
|
+
/** How far a hill reaches in from the fence: as far as it is wide (the article gives its width and no depth, so it is drawn square). */
|
|
36
|
+
const hillSpan = (q) => {
|
|
37
|
+
const half = Math.atan(q.width_ft / 2 / q.feet) / RAD;
|
|
38
|
+
return { from: Math.max(-45, q.angle - half), to: Math.min(45, q.angle + half) };
|
|
39
|
+
};
|
|
40
|
+
/** The room a ballpark's additions need: beyond the fence at the sides and top, below home plate for the backstop's bar, and under the drawing for the legend. */
|
|
41
|
+
export function ballparkRoom(b) {
|
|
42
|
+
const bands = b.walls.reduce((most, wall) => Math.max(most, bandWidth(wall.height_ft)), 0);
|
|
43
|
+
const quirks = b.quirks.some((q) => q.kind === "basket") ? 4 : 0;
|
|
44
|
+
return {
|
|
45
|
+
side: b.walls.length > 0 ? Math.max(bands + 2, quirks) : quirks,
|
|
46
|
+
below: b.backstop === undefined ? 0 : b.backstop + (b.quirkLabels ? 12 : 8),
|
|
47
|
+
legend: b.legend ? 40 : 0,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** A word on the field, upright, set inside the fence and anchored so that it runs into the field and not out of the drawing. */
|
|
51
|
+
function label(x, y, text) {
|
|
52
|
+
return textOn(false, x, y, text, { size: TEXT, anchor: x > 40 ? "end" : x < -40 ? "start" : "middle", cls: "ky-wl" });
|
|
53
|
+
}
|
|
54
|
+
function dugout(side, home) {
|
|
55
|
+
const s = side === "first" ? 1 : -1;
|
|
56
|
+
const corner = (t, o) => [s * SQ * (t + o), -SQ * (t - o)];
|
|
57
|
+
const d = `M${[corner(30, 7), corner(70, 7), corner(70, 15), corner(30, 15)].map(pt).join("L")}Z`;
|
|
58
|
+
return el("path", { class: home ? "ky-dugout" : "ky-dugout ky-dugout-away", d });
|
|
59
|
+
}
|
|
60
|
+
/** What is drawn under the lines: the hill and the overhang on the grass, the bands of the walls outside the fence, and the dugouts. */
|
|
61
|
+
export function ballparkUnder(b, points) {
|
|
62
|
+
let out = "";
|
|
63
|
+
for (const q of b.quirks) {
|
|
64
|
+
if (q.kind === "hill") {
|
|
65
|
+
const { from, to } = hillSpan(q);
|
|
66
|
+
out += el("path", { class: "ky-hill", d: strip(points, from, to, -q.width_ft, 0) });
|
|
67
|
+
}
|
|
68
|
+
else if (q.kind === "overhang")
|
|
69
|
+
out += el("path", { class: "ky-overhang", d: strip(points, q.from, q.to, -q.depth_ft, 0) });
|
|
70
|
+
}
|
|
71
|
+
for (const wall of b.walls)
|
|
72
|
+
out += el("path", { class: `ky-wall ky-wall-${tierOf(wall.height_ft)}`, d: strip(points, wall.from, wall.to, 0, bandWidth(wall.height_ft)) });
|
|
73
|
+
if (b.dugouts?.home !== undefined)
|
|
74
|
+
out += dugout(b.dugouts.home, true);
|
|
75
|
+
if (b.dugouts?.visitors !== undefined)
|
|
76
|
+
out += dugout(b.dugouts.visitors, false);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
const markOf = (q, points) => {
|
|
80
|
+
switch (q.kind) {
|
|
81
|
+
case "pole":
|
|
82
|
+
return at(q.angle, q.feet - 8);
|
|
83
|
+
case "flagpole":
|
|
84
|
+
case "bullpen": {
|
|
85
|
+
const [x, y] = at(q.angle, q.feet);
|
|
86
|
+
return [x, y + 11];
|
|
87
|
+
}
|
|
88
|
+
case "hill":
|
|
89
|
+
return at(q.angle, fenceAt(points, q.angle) - q.width_ft - 5);
|
|
90
|
+
case "overhang": {
|
|
91
|
+
const mid = (q.from + q.to) / 2;
|
|
92
|
+
return at(mid, fenceAt(points, mid) - q.depth_ft - 5);
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
/** What is drawn over the lines: the ivy and the basket, the poles and the bullpens, the backstop's bar, and the names. */
|
|
99
|
+
export function ballparkOver(b, points) {
|
|
100
|
+
let out = "";
|
|
101
|
+
for (const q of b.quirks) {
|
|
102
|
+
if (q.kind === "ivy")
|
|
103
|
+
out += el("path", { class: "ky-ivy", d: along(points, q.from, q.to, 0) });
|
|
104
|
+
else if (q.kind === "basket")
|
|
105
|
+
out += el("path", { class: "ky-basket", d: along(points, q.from, q.to, 2.5) });
|
|
106
|
+
else if (q.kind === "pole" || q.kind === "flagpole") {
|
|
107
|
+
const [x, y] = at(q.angle, q.feet);
|
|
108
|
+
out += el("circle", { class: "ky-pole", cx: x, cy: y, r: q.kind === "pole" ? 2.4 : 2 });
|
|
109
|
+
}
|
|
110
|
+
else if (q.kind === "bullpen") {
|
|
111
|
+
const [x, y] = at(q.angle, q.feet);
|
|
112
|
+
out += el("rect", { class: "ky-bullpen", x: x - 5, y: y - 3.5, width: 10, height: 7 });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (b.backstop !== undefined) {
|
|
116
|
+
out += el("path", { class: "ky-backstop", d: `M0 4V${num(b.backstop)}M-9 ${num(b.backstop)}H9`, fill: "none" });
|
|
117
|
+
if (b.quirkLabels)
|
|
118
|
+
out += textOn(false, 12, b.backstop + 2, `${lengthText(b.backstop, b.unit)} ${b.words.unit[b.unit]}`, { size: TEXT, anchor: "start", cls: "ky-wl" });
|
|
119
|
+
}
|
|
120
|
+
if (b.quirkLabels) {
|
|
121
|
+
for (const q of b.quirks) {
|
|
122
|
+
const mark = markOf(q, points);
|
|
123
|
+
if (mark === undefined)
|
|
124
|
+
continue;
|
|
125
|
+
out += label(mark[0], mark[1], quirkName(q, b.words));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (b.wallLabels) {
|
|
129
|
+
for (const wall of b.walls) {
|
|
130
|
+
const mid = (wall.from + wall.to) / 2;
|
|
131
|
+
const [x, y] = at(mid, fenceAt(points, mid) - 10);
|
|
132
|
+
out += label(x, y, wallText(wall, b));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
/** The key to the shades: a panel with its heading and the four tiers, centred under the field, its top at `y`. */
|
|
138
|
+
export function ballparkLegend(b, y) {
|
|
139
|
+
const cell = 78;
|
|
140
|
+
const texts = tierTexts(b);
|
|
141
|
+
let out = el("rect", { class: "ky-wl-p", x: -(cell + 5), y, width: 2 * cell + 10, height: 37, rx: 3 });
|
|
142
|
+
out += textOn(false, -cell, y + 10, b.words.heading, { size: TEXT, anchor: "start", cls: "ky-wl-k" });
|
|
143
|
+
texts.forEach((text, i) => {
|
|
144
|
+
const x = -cell + (i % 2) * cell;
|
|
145
|
+
const row = y + 15 + Math.floor(i / 2) * 11;
|
|
146
|
+
out += el("rect", { class: `ky-wall ky-wall-${i + 1}`, x, y: row, width: 11, height: 6 });
|
|
147
|
+
out += textOn(false, x + 15, row + 5.2, text, { size: TEXT, anchor: "start", cls: "ky-wl-k" });
|
|
148
|
+
});
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type NbaRules } from "../eras.ts";
|
|
2
|
+
import { type CourtSpec } from "../leagues/basketball.ts";
|
|
3
|
+
import { type BuildOptions, type Surface } from "./surface.ts";
|
|
4
|
+
/**
|
|
5
|
+
* A basketball court: the floor, the keys, the arcs, the circles, the baskets and the small marks. By default the NBA's, as the
|
|
6
|
+
* rules of a season (today's by default) marked it; with a `court` (leagues.ts), that league's, in feet.
|
|
7
|
+
*/
|
|
8
|
+
export declare function basketball(o: BuildOptions, era?: NbaRules, court?: CourtSpec): Surface;
|