@johnmorrisdotca/kyogijo-stadiums 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +133 -0
- package/NOTICE.md +182 -2
- package/README.md +106 -19
- package/dist/annotate.js +1 -1
- package/dist/arenas-entry.d.ts +4 -0
- package/dist/arenas-entry.js +3 -0
- package/dist/arenas.d.ts +125 -0
- package/dist/arenas.data.d.ts +2 -0
- package/dist/arenas.data.js +3763 -0
- package/dist/arenas.js +72 -0
- package/dist/athletics/describe.d.ts +8 -0
- package/dist/athletics/describe.js +41 -0
- package/dist/athletics/events.d.ts +17 -0
- package/dist/athletics/events.js +48 -0
- package/dist/athletics/facilities.d.ts +80 -0
- package/dist/athletics/facilities.js +176 -0
- package/dist/athletics/infield.d.ts +79 -0
- package/dist/athletics/infield.js +166 -0
- package/dist/athletics/layout.d.ts +13 -0
- package/dist/athletics/layout.js +98 -0
- package/dist/athletics/oval.d.ts +57 -0
- package/dist/athletics/oval.js +116 -0
- package/dist/athletics/plan.d.ts +97 -0
- package/dist/athletics/plan.js +355 -0
- package/dist/athletics/races.d.ts +102 -0
- package/dist/athletics/races.js +355 -0
- package/dist/athletics/steeplechase.d.ts +72 -0
- package/dist/athletics/steeplechase.js +196 -0
- package/dist/athletics/stencil.d.ts +13 -0
- package/dist/athletics/stencil.js +85 -0
- package/dist/athletics/track.d.ts +54 -0
- package/dist/athletics/track.js +105 -0
- package/dist/athletics/types.d.ts +77 -0
- package/dist/athletics/types.js +1 -0
- package/dist/athletics-entry.d.ts +17 -0
- package/dist/athletics-entry.js +11 -0
- package/dist/athletics.style.d.ts +16 -0
- package/dist/athletics.style.js +51 -0
- package/dist/atlas-entry.d.ts +6 -2
- package/dist/atlas-entry.js +4 -2
- package/dist/atlas.d.ts +117 -23
- package/dist/atlas.js +197 -12
- package/dist/background.js +2 -1
- package/dist/budo/describe.d.ts +13 -0
- package/dist/budo/describe.js +120 -0
- package/dist/budo/dojo.api.d.ts +64 -0
- package/dist/budo/dojo.api.js +46 -0
- package/dist/budo/dojo.d.ts +72 -0
- package/dist/budo/dojo.js +300 -0
- package/dist/budo/judo.d.ts +61 -0
- package/dist/budo/judo.js +109 -0
- package/dist/budo/karate.d.ts +29 -0
- package/dist/budo/karate.js +80 -0
- package/dist/budo/kendo.d.ts +18 -0
- package/dist/budo/kendo.js +44 -0
- package/dist/budo/kimarite.d.ts +19 -0
- package/dist/budo/kimarite.js +33 -0
- package/dist/budo/kit.d.ts +16 -0
- package/dist/budo/kit.js +24 -0
- package/dist/budo/kyudo.d.ts +28 -0
- package/dist/budo/kyudo.js +66 -0
- package/dist/budo/looks.d.ts +28 -0
- package/dist/budo/looks.js +58 -0
- package/dist/budo/parts.d.ts +32 -0
- package/dist/budo/parts.js +10 -0
- package/dist/budo/plan.d.ts +64 -0
- package/dist/budo/plan.js +139 -0
- package/dist/budo/room.d.ts +133 -0
- package/dist/budo/room.js +111 -0
- package/dist/budo/sumo.d.ts +31 -0
- package/dist/budo/sumo.js +71 -0
- package/dist/budo/tatami.d.ts +55 -0
- package/dist/budo/tatami.js +156 -0
- package/dist/budo/types.d.ts +192 -0
- package/dist/budo/types.js +2 -0
- package/dist/budo-entry.d.ts +22 -0
- package/dist/budo-entry.js +13 -0
- package/dist/budo.board.d.ts +28 -0
- package/dist/budo.board.js +81 -0
- package/dist/budo.score.d.ts +18 -0
- package/dist/budo.score.js +52 -0
- package/dist/budo.style.d.ts +6 -0
- package/dist/budo.style.js +67 -0
- package/dist/charts-entry.d.ts +6 -1
- package/dist/charts-entry.js +3 -0
- package/dist/charts.athletics.d.ts +183 -0
- package/dist/charts.athletics.js +455 -0
- package/dist/charts.baseball.js +1 -1
- package/dist/charts.curling.heat.d.ts +24 -0
- package/dist/charts.curling.heat.js +116 -0
- package/dist/charts.curling.js +14 -3
- package/dist/charts.js +4 -4
- package/dist/charts.pool.d.ts +67 -0
- package/dist/charts.pool.js +76 -0
- package/dist/charts.skating.d.ts +204 -0
- package/dist/charts.skating.js +426 -0
- package/dist/charts.soccer.js +3 -3
- package/dist/charts.types.d.ts +63 -1
- package/dist/colour.d.ts +4 -4
- package/dist/colour.js +4 -4
- package/dist/court.d.ts +85 -2
- package/dist/court.js +102 -7
- package/dist/court.more.d.ts +46 -0
- package/dist/court.more.js +219 -0
- package/dist/courts.style.d.ts +14 -2
- package/dist/courts.style.js +51 -4
- package/dist/crowd.d.ts +164 -0
- package/dist/crowd.draw.d.ts +17 -0
- package/dist/crowd.draw.js +204 -0
- package/dist/crowd.js +480 -0
- package/dist/crowd.park.d.ts +19 -0
- package/dist/crowd.park.js +153 -0
- package/dist/curling.stats.d.ts +271 -0
- package/dist/curling.stats.js +301 -0
- package/dist/draw.d.ts +16 -0
- package/dist/draw.js +462 -54
- package/dist/element-entry.d.ts +3 -1
- package/dist/element-entry.js +2 -1
- package/dist/element.d.ts +13 -2
- package/dist/element.js +79 -4
- package/dist/emblems-source.d.ts +50 -0
- package/dist/emblems-source.js +56 -0
- package/dist/eras.d.ts +3 -1
- package/dist/eras.js +8 -3
- package/dist/features.js +204 -0
- package/dist/field.data.d.ts +16 -0
- package/dist/field.data.js +50 -0
- package/dist/fields.kit.d.ts +2 -2
- package/dist/fields.types.d.ts +24 -4
- package/dist/formations.js +18 -7
- package/dist/formations.sports.d.ts +8 -0
- package/dist/formations.sports.js +251 -0
- package/dist/frames.providers.js +71 -8
- package/dist/geojson.js +3 -0
- package/dist/geometry-entry.d.ts +2 -1
- package/dist/geometry-entry.js +2 -1
- package/dist/geometry.d.ts +20 -0
- package/dist/geometry.js +78 -1
- package/dist/grounds.d.ts +4 -0
- package/dist/grounds.data.js +12 -0
- package/dist/halls.d.ts +65 -0
- package/dist/halls.js +122 -0
- package/dist/hardwood.d.ts +31 -0
- package/dist/hardwood.js +157 -0
- package/dist/heat.js +21 -13
- package/dist/heat.types.d.ts +5 -0
- package/dist/heat.zones.d.ts +4 -2
- package/dist/heat.zones.js +207 -7
- package/dist/homeside.js +24 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +18 -2
- package/dist/layers-entry.d.ts +2 -1
- package/dist/layers-entry.js +1 -0
- package/dist/layers.d.ts +2 -1
- package/dist/layers.env.d.ts +12 -1
- package/dist/layers.env.js +36 -4
- package/dist/layers.js +32 -13
- package/dist/layers.types.d.ts +9 -2
- package/dist/leagues/athletics.d.ts +63 -0
- package/dist/leagues/athletics.js +87 -0
- package/dist/leagues/budo.d.ts +196 -0
- package/dist/leagues/budo.js +105 -0
- package/dist/leagues/courts.d.ts +269 -4
- package/dist/leagues/courts.js +155 -1
- package/dist/leagues/hockey.js +41 -19
- package/dist/leagues/skating.d.ts +145 -0
- package/dist/leagues/skating.js +73 -0
- package/dist/leagues/sources.js +41 -0
- package/dist/leagues/types.d.ts +1 -1
- package/dist/leagues-entry.d.ts +4 -2
- package/dist/leagues-entry.js +2 -1
- package/dist/leagues.d.ts +17 -4
- package/dist/leagues.js +246 -5
- package/dist/lineup.codes.d.ts +23 -0
- package/dist/lineup.codes.js +122 -0
- package/dist/logo.d.ts +25 -0
- package/dist/logo.js +47 -0
- package/dist/look.d.ts +3 -3
- package/dist/look.js +39 -6
- package/dist/outline.d.ts +1 -1
- package/dist/outline.js +46 -4
- package/dist/pageant.d.ts +120 -0
- package/dist/pageant.draw.d.ts +21 -0
- package/dist/pageant.draw.js +171 -0
- package/dist/pageant.js +211 -0
- package/dist/pageant.style.d.ts +8 -0
- package/dist/pageant.style.js +42 -0
- package/dist/png.d.ts +8 -1
- package/dist/png.js +21 -1
- package/dist/pointer-entry.d.ts +2 -0
- package/dist/pointer-entry.js +2 -0
- package/dist/pointer.d.ts +113 -0
- package/dist/pointer.js +151 -0
- package/dist/pool.d.ts +176 -0
- package/dist/pool.figures.d.ts +306 -0
- package/dist/pool.figures.js +148 -0
- package/dist/pool.js +304 -0
- package/dist/pool.kit.d.ts +48 -0
- package/dist/pool.kit.js +141 -0
- package/dist/pool.labels.d.ts +20 -0
- package/dist/pool.labels.js +258 -0
- package/dist/pool.race.d.ts +65 -0
- package/dist/pool.race.js +140 -0
- package/dist/pool.replay.d.ts +46 -0
- package/dist/pool.replay.js +127 -0
- package/dist/pool.section.d.ts +13 -0
- package/dist/pool.section.js +83 -0
- package/dist/pool.style.d.ts +20 -0
- package/dist/pool.style.js +169 -0
- package/dist/pool.types.d.ts +145 -0
- package/dist/pool.types.js +3 -0
- package/dist/pool.words.d.ts +13 -0
- package/dist/pool.words.js +101 -0
- package/dist/ranges.names.js +53 -3
- package/dist/replay-entry.d.ts +3 -0
- package/dist/replay-entry.js +2 -0
- package/dist/restyle.js +1 -1
- package/dist/road.draw.js +3 -2
- package/dist/road.js +2 -1
- package/dist/road.types.d.ts +3 -0
- package/dist/rules.d.ts +138 -0
- package/dist/rules.js +511 -0
- package/dist/rules.types.d.ts +4 -0
- package/dist/rules.types.js +64 -0
- package/dist/score.d.ts +3 -0
- package/dist/score.js +93 -6
- package/dist/sheet.d.ts +3 -0
- package/dist/sheet.js +7 -3
- package/dist/situation.d.ts +135 -0
- package/dist/situation.draw.d.ts +34 -0
- package/dist/situation.draw.js +202 -0
- package/dist/situation.js +337 -0
- package/dist/situation.style.d.ts +2 -0
- package/dist/situation.style.js +45 -0
- package/dist/situation.types.d.ts +77 -0
- package/dist/situation.types.js +3 -0
- package/dist/situation.widgets.d.ts +39 -0
- package/dist/situation.widgets.js +129 -0
- package/dist/skating/describe.d.ts +7 -0
- package/dist/skating/describe.js +44 -0
- package/dist/skating/events.d.ts +24 -0
- package/dist/skating/events.js +47 -0
- package/dist/skating/figure.d.ts +24 -0
- package/dist/skating/figure.js +37 -0
- package/dist/skating/long.d.ts +54 -0
- package/dist/skating/long.js +111 -0
- package/dist/skating/parts.d.ts +43 -0
- package/dist/skating/parts.js +40 -0
- package/dist/skating/plan.d.ts +55 -0
- package/dist/skating/plan.js +197 -0
- package/dist/skating/short.d.ts +47 -0
- package/dist/skating/short.js +89 -0
- package/dist/skating/track.d.ts +66 -0
- package/dist/skating/track.js +94 -0
- package/dist/skating/types.d.ts +57 -0
- package/dist/skating/types.js +3 -0
- package/dist/skating-entry.d.ts +17 -0
- package/dist/skating-entry.js +11 -0
- package/dist/skating.style.d.ts +4 -0
- package/dist/skating.style.js +24 -0
- package/dist/strings.d.ts +470 -0
- package/dist/strings.js +674 -13
- package/dist/style.d.ts +2 -0
- package/dist/style.js +19 -2
- package/dist/surfaces/artistic.d.ts +9 -0
- package/dist/surfaces/artistic.js +94 -0
- package/dist/surfaces/athletics.d.ts +16 -0
- package/dist/surfaces/athletics.js +132 -0
- package/dist/surfaces/baseball.js +17 -0
- package/dist/surfaces/basketball.floor.d.ts +27 -0
- package/dist/surfaces/basketball.floor.js +83 -0
- package/dist/surfaces/basketball.gear.d.ts +27 -0
- package/dist/surfaces/basketball.gear.js +90 -0
- package/dist/surfaces/basketball.js +44 -22
- package/dist/surfaces/budo.d.ts +6 -0
- package/dist/surfaces/budo.js +104 -0
- package/dist/surfaces/curling.d.ts +16 -0
- package/dist/surfaces/curling.fold.d.ts +67 -0
- package/dist/surfaces/curling.fold.js +107 -0
- package/dist/surfaces/curling.js +37 -3
- package/dist/surfaces/dive.d.ts +9 -0
- package/dist/surfaces/dive.js +128 -0
- package/dist/surfaces/field.d.ts +7 -2
- package/dist/surfaces/field.js +15 -9
- package/dist/surfaces/football.js +7 -0
- package/dist/surfaces/hockey.js +4 -2
- package/dist/surfaces/net.d.ts +2 -1
- package/dist/surfaces/net.js +160 -15
- package/dist/surfaces/polo.d.ts +12 -0
- package/dist/surfaces/polo.js +159 -0
- package/dist/surfaces/pool.d.ts +27 -0
- package/dist/surfaces/pool.js +198 -0
- package/dist/surfaces/skating.d.ts +6 -0
- package/dist/surfaces/skating.js +62 -0
- package/dist/surfaces/soccer.js +2 -1
- package/dist/surfaces/surface.d.ts +76 -0
- package/dist/surfaces/venue.d.ts +15 -0
- package/dist/surfaces/venue.js +95 -0
- package/dist/target-entry.d.ts +2 -0
- package/dist/target-entry.js +2 -0
- package/dist/target.d.ts +200 -0
- package/dist/target.js +525 -0
- package/dist/team.common.d.ts +1 -1
- package/dist/team.common.js +3 -3
- package/dist/team.formation.d.ts +3 -1
- package/dist/team.formation.js +3 -3
- package/dist/team.layers.d.ts +2 -2
- package/dist/team.layers.js +4 -1
- package/dist/team.lineup.d.ts +27 -0
- package/dist/team.lineup.js +207 -0
- package/dist/team.network.js +6 -5
- package/dist/team.shape.js +5 -5
- package/dist/team.types.d.ts +40 -1
- package/dist/tenants.d.ts +77 -0
- package/dist/tenants.data.d.ts +8 -0
- package/dist/tenants.data.js +1793 -0
- package/dist/tenants.js +46 -0
- package/dist/turn-entry.d.ts +12 -0
- package/dist/turn-entry.js +7 -0
- package/dist/turn.camera.d.ts +116 -0
- package/dist/turn.camera.js +184 -0
- package/dist/turn.dom.d.ts +40 -0
- package/dist/turn.dom.js +353 -0
- package/dist/turn.kit.d.ts +86 -0
- package/dist/turn.kit.js +110 -0
- package/dist/turn.markup.d.ts +48 -0
- package/dist/turn.markup.js +108 -0
- package/dist/turn.model.d.ts +78 -0
- package/dist/turn.model.js +91 -0
- package/dist/turn.style.d.ts +5 -0
- package/dist/turn.style.js +56 -0
- package/dist/types.d.ts +221 -20
- package/dist/units.d.ts +1 -1
- package/dist/units.js +22 -1
- package/dist/uprights.board.d.ts +17 -0
- package/dist/uprights.board.js +59 -0
- package/dist/uprights.budo.d.ts +17 -0
- package/dist/uprights.budo.js +87 -0
- package/dist/uprights.d.ts +37 -0
- package/dist/uprights.fields.d.ts +32 -0
- package/dist/uprights.fields.js +172 -0
- package/dist/uprights.goal.d.ts +49 -0
- package/dist/uprights.goal.js +69 -0
- package/dist/uprights.js +169 -0
- package/dist/uprights.more.d.ts +7 -0
- package/dist/uprights.more.js +183 -0
- package/dist/uprights.net.d.ts +12 -0
- package/dist/uprights.net.js +109 -0
- package/dist/uprights.netkit.d.ts +28 -0
- package/dist/uprights.netkit.js +67 -0
- package/dist/uprights.pools.d.ts +8 -0
- package/dist/uprights.pools.js +190 -0
- package/dist/uprights.rinks.d.ts +27 -0
- package/dist/uprights.rinks.js +106 -0
- package/dist/uprights.track.d.ts +50 -0
- package/dist/uprights.track.js +246 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/zones-entry.d.ts +2 -0
- package/dist/zones-entry.js +2 -0
- package/package.json +56 -3
package/dist/courts.style.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const WALL = { light: { wall: "#4f575f", mesh: "#98a1a9" }, dark: { wall: "#8b949c", mesh: "#59626a" } };
|
|
2
|
+
// World Squash's specification asks that court markings contrast with the surfaces beside them (5.01.01) and lets them be any colour that does (10.13), the walls' lines
|
|
3
|
+
// differing from the floor's if need be. Red is the colour squash lines are painted in: ours, a red dark enough on the light floor and pale enough on the dark one to read at 3:1.
|
|
4
|
+
const FACE = { light: { face: "#efeadf", tin: "#c3c8cd", wallLine: "#a8201a" }, dark: { face: "#454b52", tin: "#34393f", wallLine: "#ffb3a8" } };
|
|
1
5
|
const NET = { light: "#20262b", dark: "#e6e9ec" };
|
|
2
6
|
/** The looks of every sport, each in light and dark. */
|
|
3
7
|
export const COURT_LOOKS = {
|
|
@@ -26,8 +30,42 @@ export const COURT_LOOKS = {
|
|
|
26
30
|
blue: { light: { surface: "#1f4f8f", free: "#1f4f8f", apron: "#cfd6df" }, dark: { surface: "#1a4079", free: "#1a4079", apron: "#1a1d21" } },
|
|
27
31
|
green: { light: { surface: "#2f6f4f", free: "#2f6f4f", apron: "#cdd6c8" }, dark: { surface: "#25583f", free: "#25583f", apron: "#1a1d1b" } },
|
|
28
32
|
},
|
|
33
|
+
padel: {
|
|
34
|
+
blue: { light: { surface: "#2f6fb5", free: "#2f6fb5", apron: "#d3d9d0", ...WALL.light }, dark: { surface: "#2a5a93", free: "#2a5a93", apron: "#1a1c1b", ...WALL.dark } },
|
|
35
|
+
green: { light: { surface: "#3f8f5f", free: "#3f8f5f", apron: "#d3d9d0", ...WALL.light }, dark: { surface: "#2e6c47", free: "#2e6c47", apron: "#1a1c1b", ...WALL.dark } },
|
|
36
|
+
terracotta: { light: { surface: "#c0623f", free: "#c0623f", apron: "#d9cdb8", ...WALL.light }, dark: { surface: "#8f4630", free: "#8f4630", apron: "#1b1f1c", ...WALL.dark } },
|
|
37
|
+
},
|
|
38
|
+
squash: {
|
|
39
|
+
wood: { light: { surface: "#d7a766", free: "#d7a766", apron: "#c9c3b4", line: "#a8201a", ...WALL.light, ...FACE.light }, dark: { surface: "#8a6638", free: "#8a6638", apron: "#1a1c1b", line: "#ffb3a8", ...WALL.dark, ...FACE.dark } },
|
|
40
|
+
blue: { light: { surface: "#4a7fb8", free: "#4a7fb8", apron: "#d3d8df", ...WALL.light, ...FACE.light }, dark: { surface: "#35608f", free: "#35608f", apron: "#1a1c1b", ...WALL.dark, ...FACE.dark } },
|
|
41
|
+
},
|
|
42
|
+
racquetball: {
|
|
43
|
+
wood: { light: { surface: "#efd9ae", free: "#efd9ae", apron: "#c9c3b4", line: "#c8372d", ...WALL.light }, dark: { surface: "#55401f", free: "#55401f", apron: "#1a1c1b", line: "#ff6b5e", ...WALL.dark } },
|
|
44
|
+
convertible: { light: { surface: "#efd9ae", free: "#efd9ae", apron: "#c9c3b4", line: "#2a5db0", ...WALL.light }, dark: { surface: "#55401f", free: "#55401f", apron: "#1a1c1b", line: "#7aa3e6", ...WALL.dark } },
|
|
45
|
+
},
|
|
46
|
+
sepaktakraw: {
|
|
47
|
+
blue: { light: { surface: "#3a73b5", free: "#2c5a91", apron: "#d3d8df" }, dark: { surface: "#2e5c92", free: "#234875", apron: "#1a1c1b" } },
|
|
48
|
+
green: { light: { surface: "#3f8f66", free: "#2f7050", apron: "#d3d9d0" }, dark: { surface: "#2d6b4c", free: "#235539", apron: "#1a1c1b" } },
|
|
49
|
+
wood: { light: { surface: "#dcae6e", free: "#c99a5c", apron: "#c9c3b4" }, dark: { surface: "#8f6a3c", free: "#7d5d35", apron: "#1a1c1b" } },
|
|
50
|
+
},
|
|
51
|
+
teqball: {
|
|
52
|
+
grey: { light: { surface: "#8d949b", free: "#8d949b", apron: "#d6d8da", table: "#2a5db0", ...WALL.light }, dark: { surface: "#5f666d", free: "#5f666d", apron: "#1a1c1d", table: "#4a78c4", ...WALL.dark } },
|
|
53
|
+
blue: { light: { surface: "#3b78b8", free: "#3b78b8", apron: "#d3d8df", table: "#e4eaef", ...WALL.light }, dark: { surface: "#2e5f95", free: "#2e5f95", apron: "#1a1c1b", table: "#aeb8c2", ...WALL.dark } },
|
|
54
|
+
green: { light: { surface: "#4d9468", free: "#4d9468", apron: "#d3d9d0", table: "#27323b", ...WALL.light }, dark: { surface: "#35704b", free: "#35704b", apron: "#1a1c1b", table: "#8696a4", ...WALL.dark } },
|
|
55
|
+
},
|
|
56
|
+
roundnet: {
|
|
57
|
+
grass: { light: { surface: "#68a653", free: "#68a653", apron: "#cfd6bd", setnet: "#e9efe4" }, dark: { surface: "#3f6e32", free: "#3f6e32", apron: "#1b1f1c", setnet: "#a9b8a2" } },
|
|
58
|
+
sand: { light: { surface: "#e3cf9a", free: "#e3cf9a", apron: "#cdbf9c", line: "#2a5db0", setnet: "#f6efd9" }, dark: { surface: "#8a784d", free: "#8a784d", apron: "#1d1c17", setnet: "#c9bd9a" } },
|
|
59
|
+
indoor: { light: { surface: "#b9b2a2", free: "#b9b2a2", apron: "#d3d0c8", setnet: "#ece9e1" }, dark: { surface: "#6f6a5f", free: "#6f6a5f", apron: "#1b1b19", setnet: "#a9a597" } },
|
|
60
|
+
},
|
|
61
|
+
netball: {
|
|
62
|
+
wood: { light: { surface: "#d9a96a", free: "#c4955a", apron: "#c9c3b4" }, dark: { surface: "#8f6a3c", free: "#7d5d35", apron: "#1a1c1b" } },
|
|
63
|
+
blue: { light: { surface: "#3d78bd", free: "#2f5f9a", apron: "#dcd8c9" }, dark: { surface: "#2f5f99", free: "#244a78", apron: "#1b1f1c" } },
|
|
64
|
+
green: { light: { surface: "#4d9468", free: "#3c7852", apron: "#dcd8c9" }, dark: { surface: "#35704b", free: "#285539", apron: "#1b1f1c" } },
|
|
65
|
+
},
|
|
29
66
|
};
|
|
30
|
-
const
|
|
67
|
+
const OPTIONAL = [["area", "--ky-area"], ["line", "--ky-line"], ["wallLine", "--ky-wall-line"], ["wall", "--ky-wall"], ["mesh", "--ky-mesh"], ["face", "--ky-face"], ["tin", "--ky-tin"], ["table", "--ky-table"], ["setnet", "--ky-setnet"]];
|
|
68
|
+
const vars = (look, net) => `--ky-surface:${look.surface};--ky-free:${look.free};--ky-apron:${look.apron};--ky-net:${net}${OPTIONAL.map(([key, name]) => (look[key] === undefined ? "" : `;${name}:${look[key]}`)).join("")}`;
|
|
31
69
|
/** The three rules of one look: light, dark by the device's setting, and dark by the page's `data-theme`. */
|
|
32
70
|
function lookRules(sport, name) {
|
|
33
71
|
const pair = COURT_LOOKS[sport][name];
|
|
@@ -46,9 +84,18 @@ const CLASSES = `
|
|
|
46
84
|
.kyogijo .ky-serve{fill:var(--ky-serve,#d8e33b);stroke:rgba(0,0,0,.45);stroke-width:.06}
|
|
47
85
|
.kyogijo .ky-serve-seam{fill:none;stroke:rgba(0,0,0,.45)}
|
|
48
86
|
.kyogijo .ky-tb{font-weight:700;opacity:.9}`.trim();
|
|
49
|
-
/** The rules of
|
|
87
|
+
/** The rules of the classes only some courts have: walls and fences, the front wall of a squash court and its lines, a teqball table and a roundnet set's net. */
|
|
88
|
+
const FIXTURES = `
|
|
89
|
+
.kyogijo .ky-wall{fill:var(--ky-wall)}
|
|
90
|
+
.kyogijo .ky-mesh{fill:var(--ky-mesh)}
|
|
91
|
+
.kyogijo .ky-face{fill:var(--ky-face)}
|
|
92
|
+
.kyogijo .ky-tin{fill:var(--ky-tin)}
|
|
93
|
+
.kyogijo .ky-wall-line{fill:var(--ky-wall-line,var(--ky-line))}
|
|
94
|
+
.kyogijo .ky-table{fill:var(--ky-table)}
|
|
95
|
+
.kyogijo .ky-set-net{fill:var(--ky-setnet)}`.trim();
|
|
96
|
+
/** The rules of a drawing of this sport in this look: the shared rules, the rules of the fixtures its sport has, and the look's colours. */
|
|
50
97
|
export function courtStyle(sport, look) {
|
|
51
|
-
return `${CLASSES}\n${lookRules(sport, look)}`;
|
|
98
|
+
return `${CLASSES}\n${COURT_LOOKS[sport][look].light.wall !== undefined || COURT_LOOKS[sport][look].light.table !== undefined || COURT_LOOKS[sport][look].light.setnet !== undefined ? `${FIXTURES}\n` : ""}${lookRules(sport, look)}`;
|
|
52
99
|
}
|
|
53
100
|
/** Every net sport's rules and every look, for a page that draws with `style: "none"` and supplies the stylesheet itself. */
|
|
54
|
-
export const KYOGIJO_COURTS_STYLE = `${CLASSES}\n${Object.keys(COURT_LOOKS).flatMap((sport) => Object.keys(COURT_LOOKS[sport]).map((name) => lookRules(sport, name))).join("\n")}`;
|
|
101
|
+
export const KYOGIJO_COURTS_STYLE = `${CLASSES}\n${FIXTURES}\n${Object.keys(COURT_LOOKS).flatMap((sport) => Object.keys(COURT_LOOKS[sport]).map((name) => lookRules(sport, name))).join("\n")}`;
|
package/dist/crowd.d.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { CrowdShape, Side, Sport, SurfaceOptions } from "./types.ts";
|
|
2
|
+
export type Pt = [number, number];
|
|
3
|
+
export type Box = {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
w: number;
|
|
7
|
+
h: number;
|
|
8
|
+
};
|
|
9
|
+
/** The outline of a part of the stands, in feet in the surface's wide frame: a rectangle with rounded corners, an ellipse, or a polygon. */
|
|
10
|
+
export type Outline = {
|
|
11
|
+
kind: "rrect";
|
|
12
|
+
x0: number;
|
|
13
|
+
y0: number;
|
|
14
|
+
x1: number;
|
|
15
|
+
y1: number;
|
|
16
|
+
r: number;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "ellipse";
|
|
19
|
+
cx: number;
|
|
20
|
+
cy: number;
|
|
21
|
+
rx: number;
|
|
22
|
+
ry: number;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "poly";
|
|
25
|
+
points: Pt[];
|
|
26
|
+
};
|
|
27
|
+
/** A tier of the stands: a band of seats between two outlines. */
|
|
28
|
+
export interface StandRing {
|
|
29
|
+
/** `lower`, `upper`, `courtside`, `grandstand` or `bleachers`, with the tier's number where a ring has parts. */
|
|
30
|
+
id: string;
|
|
31
|
+
tier: "courtside" | "gallery" | "lower" | "upper" | "grandstand" | "bleachers" | "wall";
|
|
32
|
+
/** The band is `region` less `hole` (nothing for a polygon that is the band itself). */
|
|
33
|
+
region: Outline;
|
|
34
|
+
/** Further pieces of the band that are apart from `region` (a ballpark's bleachers either side of the batter's eye). */
|
|
35
|
+
more?: Outline[];
|
|
36
|
+
hole: Outline | null;
|
|
37
|
+
/** How far the band's inner and outer edges are from the edge of the playing surface, in feet, at the sides (the ends' distances are the same plus the venue's end gap less its side gap). */
|
|
38
|
+
from: number;
|
|
39
|
+
to: number;
|
|
40
|
+
/** The height of the first and of the last row above the playing surface, in feet; `rake` is the slope between them in degrees. For a view that raises the stands. */
|
|
41
|
+
height: [number, number];
|
|
42
|
+
rake: number;
|
|
43
|
+
/** The share of its seats that are taken, relative to the stands' (the upper tier is emptier). */
|
|
44
|
+
fill: number;
|
|
45
|
+
/** The seats the band holds, at a seat's 2 by 2.3 feet. */
|
|
46
|
+
seats: number;
|
|
47
|
+
/** The aisles and vomitories across the band, each from a point on its inner edge to its outer: across the sides, fanning round the corners. */
|
|
48
|
+
aisles: [Pt, Pt][];
|
|
49
|
+
}
|
|
50
|
+
/** A block of the stands that is not the home fans': the visitors', or a card display. A polygon in the wide frame. */
|
|
51
|
+
export interface StandSector {
|
|
52
|
+
ring: string;
|
|
53
|
+
kind: "away" | "tifo-home" | "tifo-away";
|
|
54
|
+
points: Pt[];
|
|
55
|
+
}
|
|
56
|
+
/** A place left open or built on: a tunnel through the lower stands, a bench, the camera platform of the media side. A box in the wide frame. */
|
|
57
|
+
export interface StandGap {
|
|
58
|
+
kind: "tunnel" | "bench" | "media" | "camera";
|
|
59
|
+
box: [x0: number, y0: number, x1: number, y1: number];
|
|
60
|
+
}
|
|
61
|
+
/** The stands round a surface as data. */
|
|
62
|
+
export interface CrowdStands {
|
|
63
|
+
sport: Sport;
|
|
64
|
+
shape: CrowdShape;
|
|
65
|
+
/** The stadium a soccer pitch stands in: `purpose` (its own), `nfl` or `cfl` (a gridiron's), or nothing for another sport. */
|
|
66
|
+
stadium?: "purpose" | "nfl" | "cfl";
|
|
67
|
+
/** The playing surface, in the wide frame. */
|
|
68
|
+
box: Box;
|
|
69
|
+
rings: StandRing[];
|
|
70
|
+
/** Boxes where the stands are left out (the open end of a horseshoe, the ends of two sides). */
|
|
71
|
+
covers: [x0: number, y0: number, x1: number, y1: number][];
|
|
72
|
+
sectors: StandSector[];
|
|
73
|
+
gaps: StandGap[];
|
|
74
|
+
/** The walks between the tiers: a band between one tier's outer edge and the next one's inner. */
|
|
75
|
+
concourses: {
|
|
76
|
+
region: Outline;
|
|
77
|
+
hole: Outline | null;
|
|
78
|
+
}[];
|
|
79
|
+
/** A gridiron stadium's field under a soccer pitch: its outline and its two end zones, in the wide frame, so that the gap is seen. */
|
|
80
|
+
footprint?: {
|
|
81
|
+
field: Box;
|
|
82
|
+
endZones: [Box, Box];
|
|
83
|
+
};
|
|
84
|
+
/** The ground the stands need beyond the surface on each side, in feet. */
|
|
85
|
+
reach: {
|
|
86
|
+
left: number;
|
|
87
|
+
right: number;
|
|
88
|
+
top: number;
|
|
89
|
+
bottom: number;
|
|
90
|
+
};
|
|
91
|
+
/** The seats of all the stands, from the model: what a density is a share of when no capacity is given. */
|
|
92
|
+
seats: number;
|
|
93
|
+
/** 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. */
|
|
94
|
+
gallery?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** The crowd options read: every part has its value. */
|
|
97
|
+
export interface Crowd {
|
|
98
|
+
shape: CrowdShape | undefined;
|
|
99
|
+
open: "left" | "right";
|
|
100
|
+
stadium: "auto" | "purpose" | "nfl" | "cfl";
|
|
101
|
+
density: number | undefined;
|
|
102
|
+
attendance: number | undefined;
|
|
103
|
+
capacity: number | undefined;
|
|
104
|
+
seed: number;
|
|
105
|
+
home: string | undefined;
|
|
106
|
+
away: string | undefined;
|
|
107
|
+
awayEnd: "auto" | "left" | "right" | "corner" | "none";
|
|
108
|
+
tifo: "home" | "away" | "both" | undefined;
|
|
109
|
+
tifoDesign: "stripes" | "checks";
|
|
110
|
+
gaps: boolean;
|
|
111
|
+
roof: boolean;
|
|
112
|
+
wallSeats: boolean | undefined;
|
|
113
|
+
detail: "auto" | "fine" | "plain";
|
|
114
|
+
}
|
|
115
|
+
/** The crowd the options ask for, or `undefined` for none. */
|
|
116
|
+
export declare function resolveCrowd(value: SurfaceOptions["crowd"]): Crowd | undefined;
|
|
117
|
+
/** How full the stands are: a density, else attendance over capacity (the ground's, else the model's seats), else 0.85. */
|
|
118
|
+
export declare function densityOf(crowd: Crowd, seats: number, groundCapacity: number | undefined): number;
|
|
119
|
+
/** A small, fast generator (mulberry32): the same seed gives the same numbers on every machine. */
|
|
120
|
+
export declare function generator(seed: number): () => number;
|
|
121
|
+
/** The grounds of the package that are the home of an NFL or a CFL club, where a soccer pitch stands inside a gridiron's stands. From each ground's article. */
|
|
122
|
+
export declare const GRIDIRON_GROUNDS: Readonly<Record<string, "nfl" | "cfl">>;
|
|
123
|
+
/** The walls the package knows have seats on top of them, by park and the wall's label: Fenway Park's Green Monster (the Monster seats, 2003). */
|
|
124
|
+
export declare const WALL_SEATS: Readonly<Record<string, string>>;
|
|
125
|
+
/** The point of an outline hit by a ray from `(cx, cy)` at angle `a` (screen angle, y down). */
|
|
126
|
+
export declare function rayAt(o: Outline, cx: number, cy: number, a: number): Pt;
|
|
127
|
+
/** An outline as a path, drawn clockwise, or counter-clockwise when `reverse` (a hole in a band that is filled with the non-zero rule). */
|
|
128
|
+
export declare function outlinePath(o: Outline, reverse?: boolean): string;
|
|
129
|
+
/** An outline as points, for a view that raises the stands: arcs are cut into steps of about 7.5 degrees. */
|
|
130
|
+
export declare function outlinePoints(o: Outline): Pt[];
|
|
131
|
+
/** The seats of a band of the stands: its area at a seat's 2 by 2.3 feet. */
|
|
132
|
+
export declare const seatsIn: (region: Outline, hole: Outline | null) => number;
|
|
133
|
+
/** 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. */
|
|
134
|
+
export declare function rrectAt(o: Extract<Outline, {
|
|
135
|
+
kind: "rrect";
|
|
136
|
+
}>, u: number): {
|
|
137
|
+
p: Pt;
|
|
138
|
+
n: Pt;
|
|
139
|
+
};
|
|
140
|
+
/** What the layout needs of the options and the surface. */
|
|
141
|
+
export interface LayoutInput {
|
|
142
|
+
sport: Sport;
|
|
143
|
+
/** The playing surface in the wide frame. */
|
|
144
|
+
box: Box;
|
|
145
|
+
crowd: Crowd;
|
|
146
|
+
/** The side the visitors sit towards (the opposite of the home team's). */
|
|
147
|
+
awaySide: Side;
|
|
148
|
+
/** A ground's key, for the stadium a soccer pitch stands in. */
|
|
149
|
+
ground?: string;
|
|
150
|
+
/** The surface lies on an arena floor that fills most of the hall: the sport's closer stands, where it has them. */
|
|
151
|
+
arena?: boolean;
|
|
152
|
+
/** A hall's gallery instead of the sport's stands (a dojo's balcony, from `dojoRoom`): the distance of its first row from the surface, its depth and the heights of its first and last rows, in feet. */
|
|
153
|
+
gallery?: {
|
|
154
|
+
offset: number;
|
|
155
|
+
depth: number;
|
|
156
|
+
height: [number, number];
|
|
157
|
+
};
|
|
158
|
+
/** The ballpark's fence as points on the field, for a ballpark (see `parkLayout`). */
|
|
159
|
+
fence?: readonly Pt[];
|
|
160
|
+
/** The foul lines' length at the poles and the backstop's distance, for a ballpark. */
|
|
161
|
+
backstop?: number;
|
|
162
|
+
}
|
|
163
|
+
/** The layout of a sport's stands round its surface: rings, covers, sectors and gaps. For a ballpark see `parkLayout`. */
|
|
164
|
+
export declare function layoutOf(input: LayoutInput): CrowdStands;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Crowd, type CrowdStands } from "./crowd.ts";
|
|
2
|
+
/** How the crowd is drawn: the prefix of ids, the options read, the share of seats taken, the detail, and the class of the ground the stands stand on. */
|
|
3
|
+
export interface DrawInput {
|
|
4
|
+
id: string;
|
|
5
|
+
crowd: Crowd;
|
|
6
|
+
density: number;
|
|
7
|
+
fine: boolean;
|
|
8
|
+
ground: string;
|
|
9
|
+
}
|
|
10
|
+
/** The stands and the crowd as markup and the defs it uses. The markup is laid over the ground and under the surface. */
|
|
11
|
+
export declare function drawCrowd(stands: CrowdStands, o: DrawInput): {
|
|
12
|
+
defs: string;
|
|
13
|
+
markup: string;
|
|
14
|
+
over: string;
|
|
15
|
+
};
|
|
16
|
+
/** The rules of the stands and the crowd, written into a drawing that has one (and in `KYOGIJO_STYLE`, for a page that supplies the stylesheet), light and dark. */
|
|
17
|
+
export declare const KYOGIJO_CROWD_STYLE: string;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// The stands and the crowd as SVG: each tier a band of seats under a tile of a pattern, and the people in it a few dozen dots, a shirt and a head each, written once per tile
|
|
2
|
+
// (a dot is a stroke of no length with round caps, a few bytes), so that a stadium is a few shapes however many seats it has, in the home colours with the empty seats showing.
|
|
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
|
+
// the same crowd. Written for this package; no photograph or other drawing was copied.
|
|
5
|
+
import { el, num } from "./format.js";
|
|
6
|
+
import { generator, outlinePath } from "./crowd.js";
|
|
7
|
+
/** The width and the height of a tile of the crowd, in feet, and the seats' pitch. */
|
|
8
|
+
const TILE = 14.4;
|
|
9
|
+
const PITCH = 2.4;
|
|
10
|
+
const SHIRTS = ["#9aa3b0", "#3a4252", "#6a7384", "#a08f76", "#2a2c33", "#7d90a8"];
|
|
11
|
+
const HAIR = ["#17120e", "#251a12", "#3d2a1b", "#8c7040", "#5c5c5c", "#b07c5a"];
|
|
12
|
+
const n1 = (v) => {
|
|
13
|
+
const t = (Math.round(v * 10) / 10).toString();
|
|
14
|
+
return t === "-0" ? "0" : t.replace(/^0\./, ".");
|
|
15
|
+
};
|
|
16
|
+
/** One tile of people: the seats of a block 18 feet square, each taken with the probability `density`, in the colour of a team with the probability `share` and else in a neutral. */
|
|
17
|
+
function tile(seed, density, share, team, neutral = false) {
|
|
18
|
+
const next = generator(seed);
|
|
19
|
+
const shirts = new Map();
|
|
20
|
+
const heads = new Map();
|
|
21
|
+
const empty = [];
|
|
22
|
+
const put = (map, key, x, y) => {
|
|
23
|
+
const list = map.get(key) ?? [];
|
|
24
|
+
list.push(`M${n1(x)} ${n1(y)}h.01`);
|
|
25
|
+
map.set(key, list);
|
|
26
|
+
};
|
|
27
|
+
for (let j = 0; j < TILE / PITCH; j += 1) {
|
|
28
|
+
for (let i = 0; i < TILE / PITCH; i += 1) {
|
|
29
|
+
const x = (i + 0.5) * PITCH + (next() - 0.5) * 0.2;
|
|
30
|
+
const y = (j + 0.5) * PITCH + (next() - 0.5) * 0.2;
|
|
31
|
+
const taken = next() < density;
|
|
32
|
+
const shirt = next();
|
|
33
|
+
const hair = next();
|
|
34
|
+
if (!taken) {
|
|
35
|
+
empty.push(`M${n1(x)} ${n1(y)}h.01`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// A team's fans are in its colour, some of them in a darker shade of it (a jacket, a shadow), the rest in neutrals.
|
|
39
|
+
put(shirts, shirt < share * 0.72 ? team : shirt < share ? `${team}-d` : `#${SHIRTS[Math.floor(next() * SHIRTS.length)].slice(1)}`, x, y);
|
|
40
|
+
put(heads, HAIR[Math.floor(hair * HAIR.length)], x, y);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
let out = "";
|
|
44
|
+
if (empty.length > 0)
|
|
45
|
+
out += el("path", { class: neutral ? "ky-cr-seat ky-bud-gseat" : "ky-cr-seat", d: empty.join("") });
|
|
46
|
+
for (const [key, list] of shirts)
|
|
47
|
+
out += key.startsWith("ky-") ? el("path", { class: key, d: list.join("") }) : el("path", { stroke: key, d: list.join("") });
|
|
48
|
+
const headPaths = [...heads].map(([colour, list]) => el("path", { stroke: colour, "stroke-width": 1.15, d: list.join("") })).join("");
|
|
49
|
+
return el("g", { fill: "none", "stroke-linecap": "round", "stroke-width": 2.3 }, out + headPaths);
|
|
50
|
+
}
|
|
51
|
+
/** The tiles a crowd needs: the home tile, the home tile of the upper tiers (emptier) and the visitors', and the display tiles. */
|
|
52
|
+
function patterns(id, crowd, density, tifo, neutral = false) {
|
|
53
|
+
const make = (suffix, body, size = TILE) => el("pattern", { id: `${id}-cr-${suffix}`, width: size, height: size, patternUnits: "userSpaceOnUse" }, body);
|
|
54
|
+
let out = make("h", tile(crowd.seed * 7 + 1, density, neutral ? 0 : 0.88, "ky-cr-h", neutral)) + make("a", tile(crowd.seed * 7 + 3, Math.min(1, density * 1.04), 0.94, "ky-cr-a"));
|
|
55
|
+
if (tifo !== undefined) {
|
|
56
|
+
const stripes = (cls) => el("rect", { class: cls, width: 3, height: 6 }) + el("rect", { class: "ky-cr-tw", x: 3, width: 3, height: 6 });
|
|
57
|
+
const checks = (cls) => el("rect", { class: cls, width: 3, height: 3 }) + el("rect", { class: cls, x: 3, y: 3, width: 3, height: 3 }) + el("rect", { class: "ky-cr-tw", x: 3, width: 3, height: 3 }) + el("rect", { class: "ky-cr-tw", y: 3, width: 3, height: 3 });
|
|
58
|
+
const one = crowd.tifoDesign === "checks" ? checks : stripes;
|
|
59
|
+
if (tifo.home)
|
|
60
|
+
out += make("th", one("ky-cr-th"), 6);
|
|
61
|
+
if (tifo.away)
|
|
62
|
+
out += make("ta", one("ky-cr-ta"), 6);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
const path = (ring) => [ring.region, ...(ring.more ?? [])].map((o) => outlinePath(o)).join("") + (ring.hole === null ? "" : outlinePath(ring.hole, true));
|
|
67
|
+
/** The aisles of a band as one path: the lines the stands data gives, every fourth a vomitory, drawn wider. */
|
|
68
|
+
function aisles(ring) {
|
|
69
|
+
const line = ([[x0, y0], [x1, y1]]) => `M${Math.round(x0)} ${Math.round(y0)}L${Math.round(x1)} ${Math.round(y1)}`;
|
|
70
|
+
const plain = ring.aisles.filter((_, i) => i % 4 !== 0).map(line).join("");
|
|
71
|
+
const vomitories = ring.aisles.filter((_, i) => i % 4 === 0).map(line).join("");
|
|
72
|
+
return (plain === "" ? "" : el("path", { class: "ky-cr-aisle", d: plain, "stroke-width": 1.2 })) + (vomitories === "" ? "" : el("path", { class: "ky-cr-aisle", d: vomitories, "stroke-width": 2.6 }));
|
|
73
|
+
}
|
|
74
|
+
/** The pitch of the row lines, in feet: every second row of seats. */
|
|
75
|
+
const ROW = 5;
|
|
76
|
+
/** The row lines of a band, as one path: the outlines of the band's edges stepped across it, so that they follow its curves (a polygon, which has no concentric outlines, has a few). */
|
|
77
|
+
function rows(ring) {
|
|
78
|
+
const r = ring.region;
|
|
79
|
+
const h = ring.hole;
|
|
80
|
+
const d = [];
|
|
81
|
+
const depth = ring.to - ring.from;
|
|
82
|
+
if (r.kind === "rrect" && h !== null && h.kind === "rrect") {
|
|
83
|
+
// A rounded rectangle as relative arcs, a row's lines being the same shape stepped outwards.
|
|
84
|
+
const hr = Math.min(h.r, (h.x1 - h.x0) / 2, (h.y1 - h.y0) / 2);
|
|
85
|
+
for (let k = ROW; k < depth - 1; k += ROW) {
|
|
86
|
+
const rr = Math.round(hr + k);
|
|
87
|
+
const w = Math.round(h.x1 - h.x0 + 2 * k) - 2 * rr;
|
|
88
|
+
const v = Math.round(h.y1 - h.y0 + 2 * k) - 2 * rr;
|
|
89
|
+
d.push(`M${Math.round(h.x0 - k) + rr} ${Math.round(h.y0 - k)}h${w}a${rr} ${rr} 0 0 1 ${rr} ${rr}v${v}a${rr} ${rr} 0 0 1 ${-rr} ${rr}h${-w}a${rr} ${rr} 0 0 1 ${-rr} ${-rr}v${-v}a${rr} ${rr} 0 0 1 ${rr} ${-rr}z`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (r.kind === "ellipse" && h !== null && h.kind === "ellipse") {
|
|
93
|
+
for (let k = ROW; k < depth - 1; k += ROW)
|
|
94
|
+
d.push(outlinePath({ kind: "ellipse", cx: h.cx, cy: h.cy, rx: h.rx + k, ry: h.ry + k }));
|
|
95
|
+
}
|
|
96
|
+
else if (r.kind === "poly") {
|
|
97
|
+
for (const piece of [r, ...(ring.more ?? [])]) {
|
|
98
|
+
if (piece.kind !== "poly")
|
|
99
|
+
continue;
|
|
100
|
+
const pts = piece.points;
|
|
101
|
+
const m = pts.length / 2;
|
|
102
|
+
for (const f of [0.25, 0.5, 0.75])
|
|
103
|
+
d.push(`M${Array.from({ length: m }, (_, j) => `${n1(pts[j][0] + f * (pts[2 * m - 1 - j][0] - pts[j][0]))} ${n1(pts[j][1] + f * (pts[2 * m - 1 - j][1] - pts[j][1]))}`).join("L")}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return d.length === 0 ? "" : el("path", { class: "ky-cr-row", d: d.join("") });
|
|
107
|
+
}
|
|
108
|
+
const poly = (points) => `M${points.map(([x, y]) => `${Math.round(x)} ${Math.round(y)}`).join("L")}Z`;
|
|
109
|
+
/** The stands and the crowd as markup and the defs it uses. The markup is laid over the ground and under the surface. */
|
|
110
|
+
export function drawCrowd(stands, o) {
|
|
111
|
+
const { id, crowd, density, fine } = o;
|
|
112
|
+
const tifo = { home: stands.sectors.some((s) => s.kind === "tifo-home"), away: stands.sectors.some((s) => s.kind === "tifo-away") };
|
|
113
|
+
let body = "";
|
|
114
|
+
// A ballpark's stands stand on a plaza of their own, not on the grass of the foul ground.
|
|
115
|
+
if (stands.sport === "mlb")
|
|
116
|
+
for (const ring of stands.rings)
|
|
117
|
+
body += el("path", { class: "ky-cr-plaza", d: path(ring) });
|
|
118
|
+
// The walks between the tiers: a thin darker band.
|
|
119
|
+
for (const c of stands.concourses)
|
|
120
|
+
body += el("path", { class: "ky-cr-conc", d: outlinePath(c.region) + (c.hole === null ? "" : outlinePath(c.hole, true)) });
|
|
121
|
+
// A gridiron stadium's field under a soccer pitch is drawn over the pitch, faintly, so that the gap between the two is seen.
|
|
122
|
+
let over = "";
|
|
123
|
+
if (stands.footprint !== undefined) {
|
|
124
|
+
const { field, endZones } = stands.footprint;
|
|
125
|
+
over += endZones.map((z) => el("rect", { class: "ky-cr-ez", x: n1(z.x), y: n1(z.y), width: n1(z.w), height: n1(z.h) })).join("");
|
|
126
|
+
const lines = [];
|
|
127
|
+
for (let x = field.x + endZones[0].w; x <= field.x + field.w - endZones[1].w + 0.01; x += 15)
|
|
128
|
+
lines.push(`M${n1(x)} ${n1(field.y)}v${n1(field.h)}`);
|
|
129
|
+
over += el("path", { class: "ky-cr-yard", d: lines.join(""), "stroke-width": 0.5 });
|
|
130
|
+
over += el("rect", { class: "ky-cr-yard", x: n1(field.x), y: n1(field.y), width: n1(field.w), height: n1(field.h), "stroke-width": 0.9, fill: "none", "stroke-dasharray": "5 3" });
|
|
131
|
+
over = el("g", { class: "ky-cr-footprint" }, over);
|
|
132
|
+
}
|
|
133
|
+
for (const ring of stands.rings) {
|
|
134
|
+
// The upper tiers are a little emptier: their paint is the same tile with the empty seats' bed showing through a veil.
|
|
135
|
+
// The bed of seats under the tile, so that no seam of the pattern shows light.
|
|
136
|
+
const bed = stands.gallery === true ? "ky-cr-bed ky-bud-gbed" : "ky-cr-bed";
|
|
137
|
+
if (fine)
|
|
138
|
+
body += el("path", { class: bed, d: path(ring) }) + el("path", { class: "ky-cr-people", d: path(ring), fill: `url(#${id}-cr-h)` });
|
|
139
|
+
else
|
|
140
|
+
body += el("path", { class: bed, d: path(ring) }) + el("path", { class: stands.gallery === true ? "ky-cr-blk ky-bud-gblk" : "ky-cr-blk", d: path(ring), "fill-opacity": num(0.28 + 0.6 * density * ring.fill) });
|
|
141
|
+
if (fine && ring.fill < 0.95)
|
|
142
|
+
body += el("path", { class: "ky-cr-bed", d: path(ring), "fill-opacity": num(Math.min(0.5, (1 - ring.fill) * 1.6)) });
|
|
143
|
+
}
|
|
144
|
+
for (const s of stands.sectors)
|
|
145
|
+
body += sector(s, id, fine, density);
|
|
146
|
+
if (fine)
|
|
147
|
+
for (const ring of stands.rings)
|
|
148
|
+
body += rows(ring) + (stands.gallery === true ? "" : aisles(ring));
|
|
149
|
+
// Depth: the front wall of a tier throws a shade on its first rows (and the ground in front of it), the roof's edge on the last rows of the upper tier.
|
|
150
|
+
// A gallery's railing: a line along its front edge, over the seats.
|
|
151
|
+
if (stands.gallery === true)
|
|
152
|
+
for (const ring of stands.rings)
|
|
153
|
+
if (ring.hole !== null)
|
|
154
|
+
body += el("path", { class: "ky-bud-rail", d: outlinePath(ring.hole), fill: "none" });
|
|
155
|
+
if (fine && stands.gallery !== true) {
|
|
156
|
+
for (const ring of stands.rings) {
|
|
157
|
+
if (ring.hole !== null)
|
|
158
|
+
body += el("path", { d: outlinePath(ring.hole), fill: "none", stroke: "#000", "stroke-opacity": 0.2, "stroke-width": 7 });
|
|
159
|
+
if (ring.tier === "upper" && crowd.roof)
|
|
160
|
+
body += el("path", { d: outlinePath(ring.region), fill: "none", stroke: "#000", "stroke-opacity": 0.16, "stroke-width": 18 });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const [x0, y0, x1, y1] of stands.covers)
|
|
164
|
+
body += el("rect", { class: o.ground, x: n1(x0), y: n1(y0), width: n1(x1 - x0), height: n1(y1 - y0) });
|
|
165
|
+
for (const g of stands.gaps) {
|
|
166
|
+
const [x0, y0, x1, y1] = g.box;
|
|
167
|
+
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 });
|
|
168
|
+
}
|
|
169
|
+
return { defs: (fine ? patterns(id, crowd, density, tifo.home || tifo.away ? tifo : undefined, stands.gallery === true) : ""), markup: el("g", { class: "ky-crowd" }, body), over };
|
|
170
|
+
}
|
|
171
|
+
/** A block of visitors or a card display, a polygon over the band it is in. */
|
|
172
|
+
function sector(s, id, fine, density) {
|
|
173
|
+
if (s.kind === "away")
|
|
174
|
+
return fine ? el("path", { class: "ky-cr-people", d: poly(s.points), fill: `url(#${id}-cr-a)` }) : el("path", { class: "ky-cr-blk-a", d: poly(s.points), "fill-opacity": num(0.3 + 0.6 * density) });
|
|
175
|
+
const team = s.kind === "tifo-home" ? "th" : "ta";
|
|
176
|
+
return fine ? el("path", { class: "ky-cr-tifo", d: poly(s.points), fill: `url(#${id}-cr-${team})` }) : el("path", { class: s.kind === "tifo-home" ? "ky-cr-th" : "ky-cr-ta", d: poly(s.points) });
|
|
177
|
+
}
|
|
178
|
+
/** The rules of the stands and the crowd, written into a drawing that has one (and in `KYOGIJO_STYLE`, for a page that supplies the stylesheet), light and dark. */
|
|
179
|
+
export const KYOGIJO_CROWD_STYLE = `
|
|
180
|
+
:where(.kyogijo){--ky-cr-bed:#4a525d;--ky-cr-empty:#7d8794;--ky-cr-gap:#14181d;--ky-cr-conc:#8c929b;--ky-cr-rim:#1c2127;--ky-cr-dim:1}
|
|
181
|
+
@media (prefers-color-scheme:dark){:where(html:not([data-theme=light]) .kyogijo:not([data-theme=light])){--ky-cr-bed:#242a32;--ky-cr-empty:#4a535f;--ky-cr-gap:#050709;--ky-cr-conc:#2a3038;--ky-cr-rim:#07090c;--ky-cr-dim:.82}}
|
|
182
|
+
:where(html[data-theme=dark] .kyogijo,.kyogijo[data-theme=dark]){--ky-cr-bed:#242a32;--ky-cr-empty:#4a535f;--ky-cr-gap:#050709;--ky-cr-conc:#2a3038;--ky-cr-rim:#07090c;--ky-cr-dim:.82}
|
|
183
|
+
.kyogijo .ky-crowd{opacity:var(--ky-cr-dim)}
|
|
184
|
+
.kyogijo .ky-cr-bed{fill:var(--ky-cr-bed);stroke:var(--ky-cr-rim);stroke-width:1.8;stroke-opacity:.55;stroke-linejoin:round}
|
|
185
|
+
.kyogijo .ky-cr-seat{fill:none;stroke:var(--ky-cr-empty);stroke-width:1.3;stroke-opacity:.65}
|
|
186
|
+
.kyogijo .ky-cr-h{stroke:var(--ky-cr-home,var(--ky-right))}
|
|
187
|
+
.kyogijo .ky-cr-a{stroke:var(--ky-cr-away,var(--ky-left))}
|
|
188
|
+
.kyogijo .ky-cr-h-d{stroke:var(--ky-cr-home,var(--ky-right));stroke-opacity:.6}
|
|
189
|
+
.kyogijo .ky-cr-a-d{stroke:var(--ky-cr-away,var(--ky-left));stroke-opacity:.6}
|
|
190
|
+
.kyogijo .ky-cr-blk{fill:var(--ky-cr-home,var(--ky-right))}
|
|
191
|
+
.kyogijo .ky-cr-blk-a{fill:var(--ky-cr-away,var(--ky-left))}
|
|
192
|
+
.kyogijo .ky-cr-th{fill:var(--ky-cr-home,var(--ky-right))}
|
|
193
|
+
.kyogijo .ky-cr-ta{fill:var(--ky-cr-away,var(--ky-left))}
|
|
194
|
+
.kyogijo .ky-cr-tw{fill:#f2f0ea}
|
|
195
|
+
.kyogijo .ky-cr-aisle{fill:none;stroke:var(--ky-cr-gap);stroke-opacity:.8}
|
|
196
|
+
.kyogijo .ky-cr-row{fill:none;stroke:var(--ky-cr-gap);stroke-opacity:.5;stroke-width:.5}
|
|
197
|
+
.kyogijo .ky-cr-conc{fill:var(--ky-cr-conc)}
|
|
198
|
+
.kyogijo .ky-cr-tunnel{fill:#101317;fill-opacity:.72}
|
|
199
|
+
.kyogijo .ky-cr-bench{fill:#1c2127;fill-opacity:.55}
|
|
200
|
+
.kyogijo .ky-cr-media{fill:#1c2127;fill-opacity:.4}
|
|
201
|
+
.kyogijo .ky-cr-camera{fill:#1c2127;fill-opacity:.75}
|
|
202
|
+
.kyogijo .ky-cr-plaza{fill:var(--ky-apron);stroke:var(--ky-apron);stroke-width:8;stroke-linejoin:round}
|
|
203
|
+
.kyogijo .ky-cr-ez{fill:var(--ky-line);fill-opacity:.16}
|
|
204
|
+
.kyogijo .ky-cr-yard{stroke:var(--ky-line);stroke-opacity:.5;fill:none}`.trim();
|