@johnmorrisdotca/kyogijo-stadiums 0.59.0 → 0.60.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +2 -0
- package/catalogue.json +1 -1
- package/dist/catalogue.data.js +1 -1
- package/dist/element.d.ts +3 -3
- package/dist/element.js +10 -5
- package/dist/replay-entry.d.ts +2 -0
- package/dist/replay-entry.js +1 -0
- package/dist/replay.control.d.ts +4 -0
- package/dist/replay.control.js +16 -0
- package/dist/replay.dom.js +20 -3
- package/dist/replay.follow.d.ts +164 -0
- package/dist/replay.follow.dom.d.ts +30 -0
- package/dist/replay.follow.dom.js +118 -0
- package/dist/replay.follow.js +279 -0
- package/dist/replay.types.d.ts +6 -1
- package/dist/strings.core.d.ts +10 -0
- package/dist/strings.en.js +1 -0
- package/dist/strings.ja.js +1 -0
- package/dist/turn.camera.d.ts +3 -2
- package/dist/turn.camera.js +9 -4
- package/dist/turn.dom.d.ts +5 -0
- package/dist/turn.dom.js +63 -6
- package/dist/turn.follow.d.ts +22 -0
- package/dist/turn.follow.js +46 -0
- package/dist/turn.markup.d.ts +1 -1
- package/dist/turn.markup.js +2 -2
- package/dist/turn.replay.dom.d.ts +5 -0
- package/dist/turn.replay.dom.js +8 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Following the play on a 3D view: the shot of replay.follow.ts turned into what the view looks at (a point of the floor, and a zoom on top of the view's own), so that the auto-turn, the
|
|
2
|
+
// tip and every viewpoint go on as they were while the camera follows. The reader's own turn, tip or zoom holds it until Resume; a viewpoint or Reset also takes it back to the whole surface,
|
|
3
|
+
// in the same glide. It runs in the replay's own paint, inside the view's one animation frame, and never asks for a frame of its own.
|
|
4
|
+
import { outlineOf } from "./outline.js";
|
|
5
|
+
import { followRunner, zoomFor } from "./replay.follow.js";
|
|
6
|
+
import { replayPlacer, replaySnapshot } from "./replay.js";
|
|
7
|
+
/**
|
|
8
|
+
* What a 3D view looks at for a shot: the shot's middle as a point of the floor in the scene's pixels from its middle, and the zoom on top of the view's. The scene at a zoom of 1 holds more
|
|
9
|
+
* than the surface (the boards, the stands): the zoom is worked out against how much more, so that the closest shot frames the same share of the surface as a flat drawing's.
|
|
10
|
+
*/
|
|
11
|
+
export function aimOf(shot, model, surface) {
|
|
12
|
+
const s = model.scale;
|
|
13
|
+
const room = Math.hypot(model.box.x1 - model.box.x0, model.box.y1 - model.box.y0) / Math.max(1e-9, Math.hypot(surface.w * s, surface.h * s));
|
|
14
|
+
return { focus: [(shot.x - model.centre[0]) * s, (shot.y - model.centre[1]) * s], zoom: zoomFor(shot.zoom, Math.min(3, room)) };
|
|
15
|
+
}
|
|
16
|
+
/** The camera of a replay on a 3D view. `floor` is the options the floor is drawn with (the replay's), or `undefined` before it is laid. */
|
|
17
|
+
export function turnFollow(view, controller, timeline, look, floor) {
|
|
18
|
+
const surface = () => outlineOf((floor() ?? view.model().options)).box;
|
|
19
|
+
const runner = followRunner({
|
|
20
|
+
timeline,
|
|
21
|
+
now: () => view.doc.defaultView?.performance.now() ?? 0,
|
|
22
|
+
at(t, stop) {
|
|
23
|
+
const place = replayPlacer(floor() ?? view.model().options, timeline);
|
|
24
|
+
const objects = replaySnapshot(timeline, t, look).objects;
|
|
25
|
+
const placed = place(objects.map((o) => [o.x, o.y]));
|
|
26
|
+
return { box: surface(), objects: objects.map((o, i) => ({ team: o.team, x: placed[i][0], y: placed[i][1] })), stop: stop === undefined ? undefined : place([[stop[0], stop[1]]])[0] };
|
|
27
|
+
},
|
|
28
|
+
show: (shot) => view.aim(shot === undefined ? undefined : aimOf(shot, view.model(), surface())),
|
|
29
|
+
});
|
|
30
|
+
const stop = view.onUser((kind) => {
|
|
31
|
+
if (controller().state().follow === "off")
|
|
32
|
+
return;
|
|
33
|
+
controller().holdFollow(true);
|
|
34
|
+
if (kind === "preset") {
|
|
35
|
+
runner.reset();
|
|
36
|
+
view.aim(undefined, true);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
paint: (change) => runner.paint(change),
|
|
41
|
+
destroy() {
|
|
42
|
+
stop();
|
|
43
|
+
view.aim(undefined);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
package/dist/turn.markup.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export interface Layout {
|
|
|
33
33
|
* which, so that a page need not write them at all; without it every plane is laid out, as a still picture needs. `raster` is the share of its size an element is made at (`rasterOf`): each element's matrix widens it back, so that the
|
|
34
34
|
* picture is the same and the layers hold `raster` squared as many pixels.
|
|
35
35
|
*/
|
|
36
|
-
export declare function layoutOf(model: TurnModel, view: TurnView, width: number, height: number, lens?: number, cull?: boolean, raster?: Raster): Layout;
|
|
36
|
+
export declare function layoutOf(model: TurnModel, view: TurnView, width: number, height: number, lens?: number, cull?: boolean, raster?: Raster, focus?: readonly [number, number] | readonly [number, number, number]): Layout;
|
|
37
37
|
/** One plane as an element: its box in pixels and the SVG drawn on it in feet. */
|
|
38
38
|
export declare function planeMarkup(p: Plane, scale: number, transform: string, stack: number, fade?: number, raster?: number): string;
|
|
39
39
|
/**
|
package/dist/turn.markup.js
CHANGED
|
@@ -96,10 +96,10 @@ const turnedAway = (m, side) => side * (m[0] * (m[5] * m[15] - m[13] * m[7]) - m
|
|
|
96
96
|
* which, so that a page need not write them at all; without it every plane is laid out, as a still picture needs. `raster` is the share of its size an element is made at (`rasterOf`): each element's matrix widens it back, so that the
|
|
97
97
|
* picture is the same and the layers hold `raster` squared as many pixels.
|
|
98
98
|
*/
|
|
99
|
-
export function layoutOf(model, view, width, height, lens, cull = false, raster = 1) {
|
|
99
|
+
export function layoutOf(model, view, width, height, lens, cull = false, raster = 1, focus) {
|
|
100
100
|
const distance = eyeDistance(width, height, lens ?? model.lens);
|
|
101
101
|
const at = fit(model.box, { ...view, zoom: 1 }, width, height, distance);
|
|
102
|
-
const camera = cameraMatrix(view, at, distance);
|
|
102
|
+
const camera = cameraMatrix(view, at, distance, focus);
|
|
103
103
|
const s = model.scale;
|
|
104
104
|
const centre = model.centre;
|
|
105
105
|
const known = prepare(model);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { KyogijoReplay } from "./mount.ts";
|
|
2
|
+
import { type Aim } from "./turn.dom.ts";
|
|
2
3
|
import type { ReplaySettings, ReplayTimeline } from "./replay.types.ts";
|
|
3
4
|
import type { TurnModel } from "./turn.model.ts";
|
|
4
5
|
import { type TurnReplayLook } from "./turn.replay.ts";
|
|
@@ -13,6 +14,10 @@ export interface TurnInternals {
|
|
|
13
14
|
setDecorate(decorate: ((model: TurnModel) => TurnModel) | undefined, after?: () => void): void;
|
|
14
15
|
/** Paint the view as it is now: the planes whose place changed are written, the others are not touched. */
|
|
15
16
|
repaint(): void;
|
|
17
|
+
/** Look at a point of the floor with a zoom on top of the view's (a camera following the play), at once or in a glide; `undefined` gives the view back. Painted at the next `repaint`. */
|
|
18
|
+
aim(next: Aim | undefined, glide?: boolean): void;
|
|
19
|
+
/** Be told when the reader turns, tips or zooms the view (`turn`) or presses a viewpoint or Reset (`preset`). */
|
|
20
|
+
onUser(listener: (kind: "preset" | "turn") => void): () => void;
|
|
16
21
|
/** The view's own frame requests, which the auto-turn shares: one animation frame a frame, whatever runs. */
|
|
17
22
|
requestFrame(callback: FrameRequestCallback): number;
|
|
18
23
|
cancelFrame(id: number): void;
|
package/dist/turn.replay.dom.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createReplayView, replayDriver, replayPainter } from "./replay.dom.js";
|
|
|
2
2
|
import { useTurnReplay } from "./turn.dom.js";
|
|
3
3
|
import { drawFrameOf, replayPlacer, replaySnapshot } from "./replay.js";
|
|
4
4
|
import { boardFollower } from "./turn.replay.board.js";
|
|
5
|
+
import { turnFollow } from "./turn.follow.js";
|
|
5
6
|
import { keepOnFloor, moveDisc, replayTurnModel } from "./turn.replay.js";
|
|
6
7
|
/** Attach a replay to a 3D view. The controller it gives back has `destroy`, which takes the replay away and leaves the view as it was. */
|
|
7
8
|
export function attachTurnReplay(view, timeline, settings) {
|
|
@@ -57,6 +58,8 @@ export function attachTurnReplay(view, timeline, settings) {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
};
|
|
61
|
+
// The camera that follows the play.
|
|
62
|
+
const camera = turnFollow(view, () => driver.controller, timeline, look, () => laid?.floorOptions);
|
|
60
63
|
const wrap = doc.createElement("div");
|
|
61
64
|
wrap.className = "ky-replay ky-turn-replay";
|
|
62
65
|
const driver = replayDriver(doc, timeline, settings, {
|
|
@@ -65,6 +68,8 @@ export function attachTurnReplay(view, timeline, settings) {
|
|
|
65
68
|
place(t);
|
|
66
69
|
if (look.board !== false)
|
|
67
70
|
board.follow(t, view.model(), change);
|
|
71
|
+
if (change !== undefined)
|
|
72
|
+
camera.paint(change);
|
|
68
73
|
view.repaint();
|
|
69
74
|
},
|
|
70
75
|
language,
|
|
@@ -119,12 +124,15 @@ export function attachTurnReplay(view, timeline, settings) {
|
|
|
119
124
|
laid = replayTurnModel(model, timeline, driver.controller.state().t, look);
|
|
120
125
|
return laid.model;
|
|
121
126
|
}, after);
|
|
127
|
+
camera.paint({ state: driver.controller.state(), reason: "follow", crossed: [] });
|
|
128
|
+
view.repaint();
|
|
122
129
|
if (settings.autoplay === true && driver.controller.state().motion === "smooth" && doc.visibilityState !== "hidden")
|
|
123
130
|
driver.controller.play();
|
|
124
131
|
return {
|
|
125
132
|
...driver.controller,
|
|
126
133
|
destroy() {
|
|
127
134
|
driver.destroy();
|
|
135
|
+
camera.destroy();
|
|
128
136
|
root.removeEventListener("keydown", onStageKey, true);
|
|
129
137
|
if (described === null)
|
|
130
138
|
stage.removeAttribute("aria-describedby");
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The package's version: the same as package.json's, and a test holds them to each other. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.60.1";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The package's version: the same as package.json's, and a test holds them to each other. */
|
|
2
|
-
export const VERSION = "0.
|
|
2
|
+
export const VERSION = "0.60.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/kyogijo-stadiums",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.60.1",
|
|
4
4
|
"description": "Kyogijo Stadiums 競技場, 40 sports' surfaces as SVG, drawn to scale from the rulebooks: NFL, CFL and IFAF football fields, an NHL rink, an NBA court, MLB ballparks, soccer pitches, curling sheets, athletics stadiums, speed skating, short track and figure skating rinks, swimming pools, water polo fields, diving wells, artistic swimming areas, and the courts and fields of tennis, volleyball (indoor, beach and sitting), badminton, pickleball, table tennis, padel, squash, racquetball, sepak takraw, teqball, roundnet, netball, lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, and the budo of judo, karate, kendo, sumo and kyudo with a dojo of tatami laid as real units, the MMA cage, with each team's name and logo on its side and the score in the middle, stands and a crowd, a pageant of flags, and a 3D view. Light and dark, accessible, a compact badge for lists, a helper for React and a custom element. Zero dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sports",
|