@johnmorrisdotca/kyogijo-stadiums 0.24.0 → 0.27.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 +39 -0
- package/NOTICE.md +27 -0
- package/README.md +95 -59
- package/dist/crowd.d.ts +56 -2
- package/dist/crowd.draw.d.ts +3 -1
- package/dist/crowd.draw.js +27 -3
- package/dist/crowd.js +18 -10
- package/dist/district-entry.d.ts +5 -0
- package/dist/district-entry.js +4 -0
- package/dist/district.d.ts +167 -0
- package/dist/district.js +291 -0
- package/dist/district.turn.d.ts +27 -0
- package/dist/district.turn.js +157 -0
- package/dist/draw.js +22 -2
- package/dist/flythrough-entry.d.ts +8 -0
- package/dist/flythrough-entry.js +6 -0
- package/dist/flythrough.dom.d.ts +103 -0
- package/dist/flythrough.dom.js +517 -0
- package/dist/flythrough.markup.d.ts +48 -0
- package/dist/flythrough.markup.js +86 -0
- package/dist/flythrough.path.d.ts +145 -0
- package/dist/flythrough.path.js +253 -0
- package/dist/flythrough.style.d.ts +2 -0
- package/dist/flythrough.style.js +40 -0
- package/dist/flythrough.words.d.ts +33 -0
- package/dist/flythrough.words.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/stadiums-entry.d.ts +2 -0
- package/dist/stadiums-entry.js +2 -0
- package/dist/stadiums.d.ts +158 -0
- package/dist/stadiums.data.d.ts +2 -0
- package/dist/stadiums.data.js +11 -0
- package/dist/stadiums.js +210 -0
- package/dist/stadiums.osm.data.d.ts +2 -0
- package/dist/stadiums.osm.data.js +58 -0
- package/dist/strings.d.ts +17 -0
- package/dist/strings.js +2 -2
- package/dist/turn.kit.d.ts +5 -0
- package/dist/turn.markup.d.ts +7 -0
- package/dist/turn.markup.js +38 -2
- package/dist/turn.model.d.ts +4 -0
- package/dist/turn.model.js +3 -1
- package/dist/turn.style.js +6 -0
- package/dist/types.d.ts +11 -0
- package/dist/venue.d.ts +2 -0
- package/dist/venue.js +7 -4
- package/dist/venue.real.d.ts +21 -0
- package/dist/venue.real.js +150 -0
- package/dist/venues-entry.d.ts +2 -0
- package/dist/venues-entry.js +2 -0
- package/dist/venues.d.ts +153 -0
- package/dist/venues.data.d.ts +2 -0
- package/dist/venues.data.js +74 -0
- package/dist/venues.geo.d.ts +60 -0
- package/dist/venues.geo.js +211 -0
- package/dist/venues.js +213 -0
- package/dist/venues.osm.data.d.ts +4 -0
- package/dist/venues.osm.data.js +363 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +25 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type DistrictOptions, type DistrictPlan } from "./district.ts";
|
|
2
|
+
import { type PresetTable } from "./turn.camera.ts";
|
|
3
|
+
import { type KyogijoTurn } from "./turn.dom.ts";
|
|
4
|
+
import { type TurnModel, type TurnSettings } from "./turn.model.ts";
|
|
5
|
+
/** What can be asked of a district's 3D view beyond a surface's: `roof` and `roofOpen` for every venue that has one (as `venue: { roof, roofOpen }` of a single venue's view). */
|
|
6
|
+
export type DistrictTurnSettings = TurnSettings;
|
|
7
|
+
/** The four viewpoints of a district, turned with the map: the main camera looks from the south over the district (north at the top of the page), the end-on view from the west and the low corner from the south-west. */
|
|
8
|
+
export declare function districtPresets(plan: Pick<DistrictPlan, "turn">): PresetTable;
|
|
9
|
+
/**
|
|
10
|
+
* A district as a 3D model: the floor is the district's flat plan with each venue's building only, and on it stands each venue as it stands on its own (turned about the middle of its surface and moved to its place in the
|
|
11
|
+
* district), with a name over each where the district has labels. A `TurnModel` like any other: `turnMarkupOf` and `mountDistrictTurn` make a view of it.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildDistrictTurn(options: DistrictOptions, settings?: DistrictTurnSettings): TurnModel;
|
|
14
|
+
/**
|
|
15
|
+
* Mount a district as a 3D view in a container: the same view as `mountKyogijoTurn`'s, with the controls, the pointer, the keys and the auto-turn of every 3D view, over the district's plan with each venue standing on it.
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts no-run
|
|
18
|
+
* import { mountDistrictTurn } from "@johnmorrisdotca/kyogijo-stadiums/district";
|
|
19
|
+
* const view = mountDistrictTurn(document.querySelector("#city")!, { venues: ["bc-place", "rogers-arena"] }, { preset: "broadcast" });
|
|
20
|
+
* view.set({ yaw: 40 });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function mountDistrictTurn(host: HTMLElement, options: DistrictOptions, settings?: DistrictTurnSettings): KyogijoTurn<DistrictOptions>;
|
|
24
|
+
/** A district as the markup of a 3D view, still until a page's script makes it turn: pure, so a server can make it. */
|
|
25
|
+
export declare function districtTurnMarkup(options: DistrictOptions, settings?: DistrictTurnSettings): string;
|
|
26
|
+
/** The distance in feet that a number of metres is: what a test or a caller needs to compare the plan with the ground. */
|
|
27
|
+
export declare const feetOf: (metres: number) => number;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// A district in 3D: the 3D view of `turn.ts` with several real venues standing on one ground at their real relative positions and orientations. Nothing here is drawn a second way. Each venue is built as it is on its own
|
|
2
|
+
// (`buildTurn`: the stands, the walls and the roof, the goals and posts of its field), its planes are turned about the middle of its surface and moved to where the plan puts it, and the floor is the district's flat
|
|
3
|
+
// plan drawn with each venue's building only. The model it makes is a `TurnModel`, so the camera, the controls, the pointer, the auto-turn and the steady fit of every other 3D view are this one's; its
|
|
4
|
+
// buildings are stacked building by building (`Plane.group`), the far one first, so that a roof never shows through a nearer building.
|
|
5
|
+
import { describeDistrict, districtId, drawDistrict, drawMember, planDistrict, surfaceCentre } from "./district.js";
|
|
6
|
+
import { n, plane } from "./turn.kit.js";
|
|
7
|
+
import { TURN_PRESETS, wrap } from "./turn.camera.js";
|
|
8
|
+
import { mountTurn } from "./turn.dom.js";
|
|
9
|
+
import { turnMarkupOf } from "./turn.markup.js";
|
|
10
|
+
import { buildTurn, openingView, sceneBox, WORLD_PX } from "./turn.model.js";
|
|
11
|
+
import { planesOf } from "./uprights.js";
|
|
12
|
+
import { FEET_PER_METRE } from "./geometry.js";
|
|
13
|
+
import { hullOf } from "./venues.geo.js";
|
|
14
|
+
/** The four viewpoints of a district, turned with the map: the main camera looks from the south over the district (north at the top of the page), the end-on view from the west and the low corner from the south-west. */
|
|
15
|
+
export function districtPresets(plan) {
|
|
16
|
+
const turn = plan.turn;
|
|
17
|
+
return {
|
|
18
|
+
overhead: { ...TURN_PRESETS.overhead, yaw: wrap(turn) },
|
|
19
|
+
broadcast: { yaw: wrap(turn - 20), pitch: 58, zoom: 1 },
|
|
20
|
+
end: { yaw: wrap(turn - 90), pitch: 64, zoom: 1 },
|
|
21
|
+
corner: { yaw: wrap(turn - 38), pitch: 66, zoom: 1 },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Turn a point about the origin by `degrees` clockwise on the page. */
|
|
25
|
+
const rot = ([x, y], degrees) => {
|
|
26
|
+
const a = (degrees * Math.PI) / 180;
|
|
27
|
+
return [x * Math.cos(a) - y * Math.sin(a), x * Math.sin(a) + y * Math.cos(a)];
|
|
28
|
+
};
|
|
29
|
+
/** A plane of a venue's own frame (its surface's middle at `centre`) put in the district's: turned by the venue's angle about that middle and moved to where the plan puts it. */
|
|
30
|
+
function placeInDistrict(p, placed, centre, prefix, group) {
|
|
31
|
+
const at = (x, y) => {
|
|
32
|
+
const [rx, ry] = rot([x - centre[0], y - centre[1]], placed.angle);
|
|
33
|
+
return [rx + placed.at[0], ry + placed.at[1]];
|
|
34
|
+
};
|
|
35
|
+
const dir = (x, y) => rot([x, y], placed.angle);
|
|
36
|
+
const [ox, oy] = at(p.o[0], p.o[1]);
|
|
37
|
+
const [ux, uy] = dir(p.u[0], p.u[1]);
|
|
38
|
+
const [vx, vy] = dir(p.v[0], p.v[1]);
|
|
39
|
+
const moved = { ...p, id: `${prefix}${p.id}`, o: [ox, oy, p.o[2]], u: [ux, uy, p.u[2]], v: [vx, vy, p.v[2]], group };
|
|
40
|
+
if (p.shy !== undefined)
|
|
41
|
+
moved.shy = dir(p.shy[0], p.shy[1]);
|
|
42
|
+
if (p.crop === true) {
|
|
43
|
+
// A picture of the floor over a rectangle keeps its sides along x and y.
|
|
44
|
+
const corners = [at(p.o[0], p.o[1]), at(p.o[0] + p.u[0], p.o[1] + p.u[1]), at(p.o[0] + p.v[0], p.o[1] + p.v[1]), at(p.o[0] + p.u[0] + p.v[0], p.o[1] + p.u[1] + p.v[1])];
|
|
45
|
+
const [x0, x1] = [Math.min(...corners.map((c) => c[0])), Math.max(...corners.map((c) => c[0]))];
|
|
46
|
+
const [y0, y1] = [Math.min(...corners.map((c) => c[1])), Math.max(...corners.map((c) => c[1]))];
|
|
47
|
+
moved.o = [x0, y0, p.o[2]];
|
|
48
|
+
moved.u = [x1 - x0, 0, 0];
|
|
49
|
+
moved.v = [0, y1 - y0, 0];
|
|
50
|
+
}
|
|
51
|
+
return moved;
|
|
52
|
+
}
|
|
53
|
+
/** A name that faces the eye, standing over a building: its text on a plate. */
|
|
54
|
+
function sign(id, text, at, bottom, size, group) {
|
|
55
|
+
const wide = Math.max(size * 2.2, size * 0.62 * text.length + size * 1.2);
|
|
56
|
+
const tall = size * 1.7;
|
|
57
|
+
const svg = `<rect width="${n(wide)}" height="${n(tall)}" rx="${n(size * 0.3)}" class="u-signplate"/><text class="u-sign" x="${n(wide / 2)}" y="${n(tall * 0.68)}" text-anchor="middle" font-size="${n(size)}">${text.replace(/&/g, "&").replace(/</g, "<")}</text>`;
|
|
58
|
+
return { ...plane(id, "sign", [at[0] - wide / 2, at[1], bottom + tall], [wide, 0, 0], [0, 0, -tall], svg), billboard: true, lean: true, group };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A district as a 3D model: the floor is the district's flat plan with each venue's building only, and on it stands each venue as it stands on its own (turned about the middle of its surface and moved to its place in the
|
|
62
|
+
* district), with a name over each where the district has labels. A `TurnModel` like any other: `turnMarkupOf` and `mountDistrictTurn` make a view of it.
|
|
63
|
+
*/
|
|
64
|
+
export function buildDistrictTurn(options, settings = {}) {
|
|
65
|
+
const language = options.language === "ja" ? "ja" : "en";
|
|
66
|
+
const plan = planDistrict(options);
|
|
67
|
+
const base = districtId(options);
|
|
68
|
+
const id = settings.id ?? `${base}-turn`;
|
|
69
|
+
const labels = options.labels ?? plan.mode === "city";
|
|
70
|
+
const items = [];
|
|
71
|
+
const defs = [];
|
|
72
|
+
let crowdStyle = "";
|
|
73
|
+
plan.members.forEach((placed, i) => {
|
|
74
|
+
const member = placed.member;
|
|
75
|
+
const memberId = `${id}-m${i}`;
|
|
76
|
+
// Each venue is built as its own 3D view is, with the crowd drawn without its seats on its floor and the stands raised.
|
|
77
|
+
const model = buildTurn({ ...member.options, language, ...(options.theme === undefined ? {} : { theme: options.theme }), id: `${base}-m${i}` }, { ...settings, id: memberId, venue: { roof: true, ...(typeof settings.venue === "object" ? settings.venue : {}) }, preset: undefined, view: undefined });
|
|
78
|
+
const centre = surfaceCentre(member.options);
|
|
79
|
+
const prefix = `m${i}-`;
|
|
80
|
+
for (const item of model.uprights.items) {
|
|
81
|
+
const planes = item.planes.filter((p) => p.kind !== "ground").map((p) => placeInDistrict(p, placed, centre, prefix, i));
|
|
82
|
+
if (planes.length > 0) {
|
|
83
|
+
const [ax, ay] = item.at;
|
|
84
|
+
const [rx, ry] = rot([ax - centre[0], ay - centre[1]], placed.angle);
|
|
85
|
+
items.push({ ...item, id: `${prefix}${item.id}`, at: [rx + placed.at[0], ry + placed.at[1]], planes });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (model.defs !== "")
|
|
89
|
+
defs.push(model.defs);
|
|
90
|
+
if (crowdStyle === "" && model.crowdStyle !== "")
|
|
91
|
+
crowdStyle = model.crowdStyle;
|
|
92
|
+
});
|
|
93
|
+
if (labels) {
|
|
94
|
+
const size = Math.max(plan.view.w, plan.view.h) * (plan.mode === "city" ? 0.016 : 0.022);
|
|
95
|
+
plan.members.forEach((placed, i) => {
|
|
96
|
+
const top = Math.max(...items.filter((it) => it.id.startsWith(`m${i}-`)).map((it) => it.height), 60);
|
|
97
|
+
const middle = [placed.footprint.reduce((s, p) => s + p[0], 0) / placed.footprint.length, placed.footprint.reduce((s, p) => s + p[1], 0) / placed.footprint.length];
|
|
98
|
+
items.push({ id: `m${i}-name`, kind: "scoreboard", at: middle, height: top + size * 1.7, planes: [sign(`m${i}-name`, placed.member.name[language], middle, top + size * 0.6, size, i)] });
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const view = plan.view;
|
|
102
|
+
const scale = WORLD_PX / Math.max(view.w, view.h);
|
|
103
|
+
const centre = [view.x + view.w / 2, view.y + view.h / 2];
|
|
104
|
+
const area = { x0: view.x, y0: view.y, x1: view.x + view.w, y1: view.y + view.h };
|
|
105
|
+
const uprights = { items, lift: 0, thin: Math.hypot(view.w, view.h) * 0.0012, area, whole: true, ...(defs.length === 0 ? {} : { defs: defs.join("") }) };
|
|
106
|
+
const planes = planesOf(uprights);
|
|
107
|
+
const box = sceneBox(planes, area, 0, centre, scale);
|
|
108
|
+
// (The floor has no names: the 3D view's own signs, which face the eye, carry them.)
|
|
109
|
+
const floor = drawDistrict({ ...options, id: base, labels: false }, plan, (member, i) => drawMember(member, { ...options, id: base }, i, base, { floor: true }));
|
|
110
|
+
const { title, description } = describeDistrict(options, plan);
|
|
111
|
+
const presets = districtPresets(plan);
|
|
112
|
+
const surfaceLike = { sport: "soccer", language, ...(options.theme === undefined ? {} : { theme: options.theme }), ...(options.style === undefined ? {} : { style: options.style }) };
|
|
113
|
+
return {
|
|
114
|
+
id,
|
|
115
|
+
language,
|
|
116
|
+
options: surfaceLike,
|
|
117
|
+
title,
|
|
118
|
+
description,
|
|
119
|
+
standing: "",
|
|
120
|
+
floor,
|
|
121
|
+
viewBox: { x: view.x, y: view.y, w: view.w, h: view.h },
|
|
122
|
+
scale,
|
|
123
|
+
uprights,
|
|
124
|
+
defs: defs.join(""),
|
|
125
|
+
crowdStyle,
|
|
126
|
+
venue: true,
|
|
127
|
+
look: undefined,
|
|
128
|
+
planes,
|
|
129
|
+
box,
|
|
130
|
+
centre,
|
|
131
|
+
view: openingView(settings, presets),
|
|
132
|
+
turnable: true,
|
|
133
|
+
presets,
|
|
134
|
+
// A scene that turns about its middle with buildings far from it wants a longer lens, so that what swings toward the eye does not swell.
|
|
135
|
+
lens: 12,
|
|
136
|
+
flat: drawDistrict(options, plan),
|
|
137
|
+
groups: plan.members.map((p) => ({ hull: hullOf(p.footprint) })),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Mount a district as a 3D view in a container: the same view as `mountKyogijoTurn`'s, with the controls, the pointer, the keys and the auto-turn of every 3D view, over the district's plan with each venue standing on it.
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts no-run
|
|
144
|
+
* import { mountDistrictTurn } from "@johnmorrisdotca/kyogijo-stadiums/district";
|
|
145
|
+
* const view = mountDistrictTurn(document.querySelector("#city")!, { venues: ["bc-place", "rogers-arena"] }, { preset: "broadcast" });
|
|
146
|
+
* view.set({ yaw: 40 });
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function mountDistrictTurn(host, options, settings = {}) {
|
|
150
|
+
return mountTurn(host, options, settings, buildDistrictTurn);
|
|
151
|
+
}
|
|
152
|
+
/** A district as the markup of a 3D view, still until a page's script makes it turn: pure, so a server can make it. */
|
|
153
|
+
export function districtTurnMarkup(options, settings = {}) {
|
|
154
|
+
return turnMarkupOf(buildDistrictTurn(options, settings), settings);
|
|
155
|
+
}
|
|
156
|
+
/** The distance in feet that a number of metres is: what a test or a caller needs to compare the plan with the ground. */
|
|
157
|
+
export const feetOf = (metres) => metres * FEET_PER_METRE;
|
package/dist/draw.js
CHANGED
|
@@ -10,6 +10,8 @@ import { ERA_SPORTS, footballIn, rulesFor, seasonLabel } from "./eras.js";
|
|
|
10
10
|
import { FOOTBALL } from "./geometry.js";
|
|
11
11
|
import { renderLayers } from "./layers.js";
|
|
12
12
|
import { arenaById, arenaCourtIn, arenaNameIn, arenaOfficialName, arenaRinkIn } from "./arenas.js";
|
|
13
|
+
import { venueById, venueBowl } from "./venues.js";
|
|
14
|
+
import { groundOfStadium, stadiumBowl, stadiumById, stadiumConfigOf, stadiumSeats } from "./stadiums.js";
|
|
13
15
|
import { groundById, groundNameIn, groundOfficialName } from "./grounds.js";
|
|
14
16
|
import { BOARD, courtFor, hasSetsBoard, isNetLeague, isNetSport } from "./court.js";
|
|
15
17
|
import { cricketBoardMarkup } from "./cricket.board.js";
|
|
@@ -428,10 +430,21 @@ function standsFor(o, surface, crowd) {
|
|
|
428
430
|
const walls = park === undefined || crowd.wallSeats === false ? [] : parkWallsIn(park, o.year).filter((w) => (crowd.wallSeats === true ? w.height_ft >= 25 : w.label !== undefined && WALL_SEATS[park.id] === w.label));
|
|
429
431
|
return parkLayout({ fence: fenceOutline(points), backstop, crowd, seatsOnWalls: walls.map((w) => ({ from: w.from, to: w.to, height: w.height_ft })) });
|
|
430
432
|
}
|
|
433
|
+
// An arena's real venue: the building it stands in and a bowl fitted to it, where the package has one for the arena and no league of the caller's own sets the surface.
|
|
434
|
+
const box = surface.whole ?? surface.box ?? { x: 0, y: 0, w: 100, h: 100 };
|
|
435
|
+
const venue = crowd.real && sport === "nhl" && chooseLeague(o).league === undefined ? venueById(o.arena) : undefined;
|
|
436
|
+
// (No visitors' block: no source says where a real arena puts them.)
|
|
437
|
+
if (venue !== undefined)
|
|
438
|
+
return crowdLayout({ sport, box, crowd: crowd.awayEnd === "auto" ? { ...crowd, awayEnd: "none" } : crowd, awaySide, real: venueBowl(venue, box) });
|
|
439
|
+
// A football field or a soccer pitch in a real stadium: its building and a bowl of the configuration's seats.
|
|
440
|
+
const config = crowd.real ? stadiumConfigOf(sport) : undefined;
|
|
441
|
+
const stadium = config !== undefined && chooseLeague(o).league === undefined ? stadiumById(o.stadium ?? o.ground) : undefined;
|
|
442
|
+
if (stadium !== undefined && config !== undefined)
|
|
443
|
+
return crowdLayout({ sport, box, crowd: crowd.awayEnd === "auto" ? { ...crowd, awayEnd: "none" } : crowd, awaySide, real: stadiumBowl(stadium, config, box) });
|
|
431
444
|
// A dojo's crowd sits in its gallery, from the room's balcony data (in feet here); the arenas (the Budokan, the Kokugikan) keep their bowls.
|
|
432
445
|
const hall = sport === "dojo" ? dojoGallery(o) : undefined;
|
|
433
446
|
const gallery = hall === undefined ? undefined : { offset: hall.offset / 0.3048, depth: hall.depth / 0.3048, height: [hall.height[0] / 0.3048, hall.height[1] / 0.3048], rows: hall.rows, aisles: hall.aisles };
|
|
434
|
-
return crowdLayout({ sport, box
|
|
447
|
+
return crowdLayout({ sport, box, crowd, awaySide, ground: o.ground, arena: o.budo?.hall === "budokan", ...(gallery === undefined ? {} : { gallery }) });
|
|
435
448
|
}
|
|
436
449
|
/** True when the drawing is asked to be small: `detail: "simple"` or a `width` under 480 pixels. */
|
|
437
450
|
const smallDrawing = (o) => {
|
|
@@ -716,7 +729,14 @@ export function describe(o) {
|
|
|
716
729
|
const special = specialText(o, language, surfaceName);
|
|
717
730
|
// What the arena says about the size: that it is the one its sources publish, or that its rink is said to have been shorter and no size is given.
|
|
718
731
|
const arenaLine = arenaName === undefined ? "" : `${arenaSize !== undefined ? `${gap}${fill(words.said.arenaSize, { arena: arenaName })}` : sport === "nhl" && arena?.rinkUnknown === true ? `${gap}${fill(words.said.arenaUnknown, { arena: arenaName })}` : ""}${officially(arena === undefined ? undefined : arenaOfficialName(arena, language, year))}`;
|
|
719
|
-
|
|
732
|
+
// The stands of a real venue say what they are: a plausible bowl, and how the rink lies in the building.
|
|
733
|
+
const realCrowd = o.crowd === undefined || o.crowd === false ? undefined : resolveCrowd(o.crowd);
|
|
734
|
+
const venue = sport === "nhl" && league === undefined && realCrowd?.real === true ? venueById(o.arena) : undefined;
|
|
735
|
+
const realLine = venue === undefined || arenaName === undefined ? "" : `${gap}${fill(words.said.real, { arena: arenaName, seats: String(venue.seats.hockey), tiers: String(venue.tiers.count) })}${gap}${words.said[venue.osm.axis.basis === "mapped" ? "realMapped" : venue.osm.axis.basis === "building" ? "realBuilding" : "realNone"]}`;
|
|
736
|
+
const config = realCrowd?.real === true ? stadiumConfigOf(sport) : undefined;
|
|
737
|
+
const realStadium = config !== undefined && league === undefined ? stadiumById(o.stadium ?? o.ground) : undefined;
|
|
738
|
+
const stadiumLine = realStadium === undefined || config === undefined ? "" : `${gap}${fill(words.said.stadium, { stadium: groundNameIn(groundOfStadium(realStadium), o.year, language), seats: String(stadiumSeats(realStadium, config)), tiers: String(realStadium.tiers.count) })}${gap}${words.said[realStadium.osm.axis.basis === "opening" ? "stadiumOpening" : realStadium.osm.axis.basis === "building" ? "stadiumBuilding" : "stadiumNone"]}`;
|
|
739
|
+
const parkLine = (parkName === undefined ? `${groundLine}${halfLine}${arenaLine}${realLine}${stadiumLine}` : `${gap}${fill(words.said.park, { park: parkName })}${officially(parkOfficial)}${ballpark === undefined ? "" : ballparkSentences(ballpark).map((line) => `${gap}${line}`).join("")}`) + (special === undefined ? "" : `${gap}${special.text}`);
|
|
720
740
|
// A drawing of a past season says which: the markings are those of that season.
|
|
721
741
|
const dated = typeof o.year === "number" && Number.isFinite(o.year);
|
|
722
742
|
const eraLine = dated && league !== undefined
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { mountFlythrough } from "./flythrough.dom.ts";
|
|
2
|
+
export type { Flythrough, FlythroughOptions, FlythroughSettings, FlythroughStart } from "./flythrough.dom.ts";
|
|
3
|
+
export { CHANNELS, PACE, RAMP, STAGE_IDS, cameraAt, flightPlan, foldTime, glide, glideSeconds, mainView, mapBox, mapFrame, monotoneSlopes, nextRate, stageAt, startOf, stagesOf } from "./flythrough.path.ts";
|
|
4
|
+
export type { Camera, Channel, Flight, FlightInput, Keyframe, MapFrame, StageId } from "./flythrough.path.ts";
|
|
5
|
+
export { flythroughMarkup, graticuleMarkup, mapMarkup } from "./flythrough.markup.ts";
|
|
6
|
+
export { FLYTHROUGH_STYLE } from "./flythrough.style.ts";
|
|
7
|
+
export { FLYTHROUGH_WORDS } from "./flythrough.words.ts";
|
|
8
|
+
export type { FlythroughWords } from "./flythrough.words.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// The fly-through: one smooth camera from a map to the real arena, over the map (chizu's, handed over), the building's site plan and the 3D arena.
|
|
2
|
+
export { mountFlythrough } from "./flythrough.dom.js";
|
|
3
|
+
export { CHANNELS, PACE, RAMP, STAGE_IDS, cameraAt, flightPlan, foldTime, glide, glideSeconds, mainView, mapBox, mapFrame, monotoneSlopes, nextRate, stageAt, startOf, stagesOf } from "./flythrough.path.js";
|
|
4
|
+
export { flythroughMarkup, graticuleMarkup, mapMarkup } from "./flythrough.markup.js";
|
|
5
|
+
export { FLYTHROUGH_STYLE } from "./flythrough.style.js";
|
|
6
|
+
export { FLYTHROUGH_WORDS } from "./flythrough.words.js";
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type Camera, type StageId } from "./flythrough.path.ts";
|
|
2
|
+
import type { Language } from "./types.ts";
|
|
3
|
+
/** A map to start on: chizu's world (or any map of the same shape) with chizu's `drawChizu` and `projectPoint`, which are handed over, not imported, so that the package has no dependency. */
|
|
4
|
+
export interface FlythroughStart<M extends {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
} = {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}> {
|
|
11
|
+
/** The map: chizu's `WORLD`, for instance. */
|
|
12
|
+
map?: M;
|
|
13
|
+
/** Draws the map as an SVG string: chizu's `drawChizu`. It is called with `{ style: true, language }`. */
|
|
14
|
+
draw?: (map: M, options: {
|
|
15
|
+
style: boolean;
|
|
16
|
+
language: Language;
|
|
17
|
+
}) => string;
|
|
18
|
+
/** Puts a longitude and latitude on the map's canvas: chizu's `projectPoint`; `null` where the map has no place for it. */
|
|
19
|
+
project?: (map: M, lon: number, lat: number) => readonly [number, number] | null;
|
|
20
|
+
/** The metres the container's width shows at the start. 9,000 km by default. */
|
|
21
|
+
span?: number;
|
|
22
|
+
/** Where the camera starts looking, `[longitude, latitude]`: the arena stands off the middle of the screen and comes to the middle as the camera falls. The arena itself by default. */
|
|
23
|
+
centre?: readonly [number, number];
|
|
24
|
+
}
|
|
25
|
+
/** What a fly-through is of. */
|
|
26
|
+
export interface FlythroughOptions<M extends {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
} = {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
}> {
|
|
33
|
+
/** The arena's key in `ARENAS`: an arena that has a real venue (`VENUE_IDS`). */
|
|
34
|
+
arena: string;
|
|
35
|
+
start?: FlythroughStart<M>;
|
|
36
|
+
/** The stages to fly, in the order of the path; all of them by default. */
|
|
37
|
+
stages?: readonly StageId[];
|
|
38
|
+
language?: Language;
|
|
39
|
+
/** `light` or `dark`; the device's setting decides when it is left out. */
|
|
40
|
+
theme?: "light" | "dark";
|
|
41
|
+
}
|
|
42
|
+
/** How it behaves. */
|
|
43
|
+
export interface FlythroughSettings {
|
|
44
|
+
/** `auto` (the default) flies unless the reader prefers reduced motion, and then shows each stage as a still; `smooth` flies anyway and `none` shows stills. */
|
|
45
|
+
motion?: "auto" | "smooth" | "none";
|
|
46
|
+
/** Whether it starts flying when it is mounted (it does by default, unless the reader prefers reduced motion). */
|
|
47
|
+
autoPlay?: boolean;
|
|
48
|
+
/** How many times faster than the path's own pace the clock runs. 1 by default. */
|
|
49
|
+
speed?: number;
|
|
50
|
+
/** Whether the buttons under the stage are drawn. True when left out; the keys work either way. */
|
|
51
|
+
controls?: boolean;
|
|
52
|
+
/** The prefix of the ids in the page, for a page with more than one. */
|
|
53
|
+
id?: string;
|
|
54
|
+
/** Called with the stage when the camera enters one. */
|
|
55
|
+
onStage?: (stage: StageId) => void;
|
|
56
|
+
/** Called with `true` when it starts flying and `false` when it stops. */
|
|
57
|
+
onPlayChange?: (playing: boolean) => void;
|
|
58
|
+
}
|
|
59
|
+
/** What `mountFlythrough` gives back. */
|
|
60
|
+
export interface Flythrough {
|
|
61
|
+
/** `motion` flies; `stages` shows each stage as a still. */
|
|
62
|
+
readonly mode: "motion" | "stages";
|
|
63
|
+
readonly playing: boolean;
|
|
64
|
+
/** The stage the camera is in. */
|
|
65
|
+
readonly stage: StageId;
|
|
66
|
+
/** The stages flown, in order. */
|
|
67
|
+
readonly stages: readonly StageId[];
|
|
68
|
+
/** Seconds along the path now. */
|
|
69
|
+
readonly time: number;
|
|
70
|
+
/** The seconds the path takes from the first stage to the last one's start (and then the arena turns for ever). */
|
|
71
|
+
readonly duration: number;
|
|
72
|
+
/** The camera now. */
|
|
73
|
+
camera(): Camera;
|
|
74
|
+
play(): void;
|
|
75
|
+
pause(): void;
|
|
76
|
+
/** Play when paused, pause when playing; gives whether it plays now. */
|
|
77
|
+
toggle(): boolean;
|
|
78
|
+
/** Go to the stage after this one (the last one stays), and to the one before (the first starts again). */
|
|
79
|
+
next(): void;
|
|
80
|
+
back(): void;
|
|
81
|
+
/** Go to a stage (its name or its place in `stages`): the camera glides there along the path, or shows its still. */
|
|
82
|
+
goTo(stage: StageId | number): void;
|
|
83
|
+
/** Put the camera at a moment of the path at once, whatever the mode (a scrubber, a test). */
|
|
84
|
+
seek(seconds: number): void;
|
|
85
|
+
destroy(): void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Mount a fly-through of an arena in a container: a map that falls to the city and the building, which rises into the arena in 3D, turning.
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts no-run
|
|
91
|
+
* import { mountFlythrough } from "@johnmorrisdotca/kyogijo-stadiums/flythrough";
|
|
92
|
+
* import WORLD from "@johnmorrisdotca/chizu/world";
|
|
93
|
+
* import { drawChizu } from "@johnmorrisdotca/chizu/draw";
|
|
94
|
+
* import { projectPoint } from "@johnmorrisdotca/chizu";
|
|
95
|
+
*
|
|
96
|
+
* const trip = mountFlythrough(document.querySelector("#trip")!, { arena: "honda-center", start: { map: WORLD, draw: drawChizu, project: projectPoint } });
|
|
97
|
+
* trip.goTo("city");
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare function mountFlythrough<M extends {
|
|
101
|
+
width: number;
|
|
102
|
+
height: number;
|
|
103
|
+
}>(host: HTMLElement, options: FlythroughOptions<M>, settings?: FlythroughSettings): Flythrough;
|