@johnmorrisdotca/kyogijo-stadiums 0.6.2 → 0.8.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 +25 -0
- package/README.md +2 -2
- package/dist/budo/looks.js +1 -1
- package/dist/budo/room.d.ts +34 -2
- package/dist/budo/room.js +39 -7
- package/dist/budo/types.d.ts +6 -1
- package/dist/budo.style.d.ts +1 -1
- package/dist/budo.style.js +6 -3
- package/dist/charts-entry.d.ts +0 -3
- package/dist/charts-entry.js +1 -3
- package/dist/crowd.d.ts +4 -0
- package/dist/crowd.draw.d.ts +5 -0
- package/dist/crowd.draw.js +34 -5
- package/dist/crowd.js +6 -1
- package/dist/draw.js +6 -3
- package/dist/element.d.ts +3 -3
- package/dist/element.js +16 -2
- package/dist/halls.js +4 -3
- package/dist/layout.js +1 -2
- package/dist/mark.d.ts +1 -1
- package/dist/mark.js +1 -1
- package/dist/strings.d.ts +7 -29
- package/dist/strings.js +6 -24
- package/dist/style.js +1 -2
- package/dist/surfaces/budo.js +22 -2
- package/dist/turn-entry.d.ts +2 -0
- package/dist/turn-entry.js +1 -0
- package/dist/turn.dom.d.ts +8 -0
- package/dist/turn.dom.js +147 -8
- package/dist/turn.kit.d.ts +5 -3
- package/dist/turn.kit.js +1 -1
- package/dist/turn.markup.d.ts +8 -1
- package/dist/turn.markup.js +18 -4
- package/dist/turn.model.d.ts +26 -0
- package/dist/turn.model.js +34 -3
- package/dist/turn.style.js +58 -4
- package/dist/uprights.d.ts +7 -0
- package/dist/uprights.js +15 -1
- package/dist/venue.d.ts +31 -0
- package/dist/venue.geom.d.ts +53 -0
- package/dist/venue.geom.js +225 -0
- package/dist/venue.js +172 -0
- package/dist/venue.room.d.ts +9 -0
- package/dist/venue.room.js +240 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/road.d.ts +0 -26
- package/dist/road.draw.d.ts +0 -6
- package/dist/road.draw.js +0 -270
- package/dist/road.js +0 -60
- package/dist/road.model.d.ts +0 -63
- package/dist/road.model.js +0 -215
- package/dist/road.style.d.ts +0 -7
- package/dist/road.style.js +0 -26
- package/dist/road.types.d.ts +0 -125
- package/dist/road.types.js +0 -1
package/dist/mark.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// The round team mark: a flag or a logo clipped to a circle with a thin ring, or, when a team has no picture, its initials on its colour. One function draws it for the
|
|
2
|
-
// score on a surface (a banner at each end, the badge and the strip under a compact card)
|
|
2
|
+
// score on a surface (a banner at each end, the badge and the strip under a compact card), so a country has the same mark everywhere.
|
|
3
3
|
import { inkOn, safeColour } from "./colour.js";
|
|
4
4
|
import { el, esc, num } from "./format.js";
|
|
5
5
|
import { textWidth } from "./text.js";
|
package/dist/strings.d.ts
CHANGED
|
@@ -901,34 +901,6 @@ export interface KyogijoWords {
|
|
|
901
901
|
cell: string;
|
|
902
902
|
listSep: string;
|
|
903
903
|
};
|
|
904
|
-
/**
|
|
905
|
-
* The words of the road-to-the-final chart (`roadToFinal`): its title when the caller gives none, the names of the soccer knockout rounds (any other round is named by
|
|
906
|
-
* the caller, or by its own key), how a match was decided (`ft`, `aet`, `pens` with {a} and {b}), the results, the table's headings and caption, and the summary.
|
|
907
|
-
*/
|
|
908
|
-
road: {
|
|
909
|
-
title: string;
|
|
910
|
-
vs: string;
|
|
911
|
-
group: string;
|
|
912
|
-
rounds: Record<"round-of-32" | "round-of-16" | "quarter-final" | "semi-final" | "final", string>;
|
|
913
|
-
ft: string;
|
|
914
|
-
aet: string;
|
|
915
|
-
pens: string;
|
|
916
|
-
won: string;
|
|
917
|
-
lost: string;
|
|
918
|
-
drew: string;
|
|
919
|
-
tableTeam: string;
|
|
920
|
-
tableRound: string;
|
|
921
|
-
tableOpponent: string;
|
|
922
|
-
tableScore: string;
|
|
923
|
-
tableDecided: string;
|
|
924
|
-
tableResult: string;
|
|
925
|
-
caption: string;
|
|
926
|
-
name: string;
|
|
927
|
-
summary: string;
|
|
928
|
-
final: string;
|
|
929
|
-
champion: string;
|
|
930
|
-
toPlay: string;
|
|
931
|
-
};
|
|
932
904
|
/** The words of a replay: its summary, its marks, what is announced when something happens, and the controls under it. */
|
|
933
905
|
replay: {
|
|
934
906
|
/** The first sentence of the summary: {time} is the length. */
|
|
@@ -1004,6 +976,12 @@ export interface KyogijoWords {
|
|
|
1004
976
|
lower: string;
|
|
1005
977
|
zoomIn: string;
|
|
1006
978
|
zoomOut: string;
|
|
979
|
+
/** The auto-turn: the button's name (its state is `aria-pressed`), what its tooltip says to press for, and what is announced when it starts and stops. */
|
|
980
|
+
play: string;
|
|
981
|
+
playOn: string;
|
|
982
|
+
playOff: string;
|
|
983
|
+
announcePlay: string;
|
|
984
|
+
announcePause: string;
|
|
1007
985
|
/** What is announced after a key or a button: {name} for a viewpoint, and the angles: {yaw} and {pitch} in degrees. */
|
|
1008
986
|
announce: string;
|
|
1009
987
|
announceAngle: string;
|
|
@@ -1015,7 +993,7 @@ export interface KyogijoWords {
|
|
|
1015
993
|
item: string;
|
|
1016
994
|
itemSag: string;
|
|
1017
995
|
/** The names of what stands on the surface, by kind. */
|
|
1018
|
-
parts: Record<"scoreboard" | "net" | "antennae" | "goalposts" | "netposts" | "hoop" | "goal" | "boards" | "stumps" | "pylons" | "flags" | "fence" | "backstop" | "foul-poles" | "table-legs" | "walls" | "starting-blocks" | "backstroke-flags" | "false-start-rope" | "springboards" | "platforms" | "judges-stand" | "hurdles" | "steeplechase" | "high-jump" | "pole-vault" | "cage" | "padding" | "rink-boards" | "mound" | "azuchi" | "targets", string>;
|
|
996
|
+
parts: Record<"scoreboard" | "net" | "antennae" | "goalposts" | "netposts" | "hoop" | "goal" | "boards" | "stumps" | "pylons" | "flags" | "fence" | "backstop" | "foul-poles" | "table-legs" | "walls" | "starting-blocks" | "backstroke-flags" | "false-start-rope" | "springboards" | "platforms" | "judges-stand" | "hurdles" | "steeplechase" | "high-jump" | "pole-vault" | "cage" | "padding" | "rink-boards" | "mound" | "azuchi" | "targets" | "stands" | "wall-seats" | "roof" | "gallery" | "dais" | "banner" | "shrine" | "mat-edge", string>;
|
|
1019
997
|
};
|
|
1020
998
|
/** The names of the zones that `zoneAt` answers with (rules.ts), by id. */
|
|
1021
999
|
rules: Record<RuleId, string>;
|
package/dist/strings.js
CHANGED
|
@@ -414,16 +414,6 @@ export const KYOGIJO_STRINGS = {
|
|
|
414
414
|
},
|
|
415
415
|
},
|
|
416
416
|
grid: { title: "A grid of drawings ({n})", drawings: "Drawings ({n}): {list}.", key: "Key: {list}.", cell: "Drawing {n} of {total}", listSep: "; " },
|
|
417
|
-
road: {
|
|
418
|
-
title: "Road to the final", vs: "v", group: "Group stage",
|
|
419
|
-
rounds: { "round-of-32": "Round of 32", "round-of-16": "Round of 16", "quarter-final": "Quarter-final", "semi-final": "Semi-final", final: "Final" },
|
|
420
|
-
ft: "FT", aet: "AET", pens: "{a}-{b} pens", won: "Won", lost: "Lost", drew: "Drew",
|
|
421
|
-
tableTeam: "Team", tableRound: "Round", tableOpponent: "Opponent", tableScore: "Score", tableDecided: "Decided", tableResult: "Result",
|
|
422
|
-
caption: "{a} and {b}: every match on the way to the final. Scores are written with the team in the first column first.",
|
|
423
|
-
name: "{a} and {b}: {title}",
|
|
424
|
-
summary: "{a} played {an} matches on the way to the final and {b} played {bn}.",
|
|
425
|
-
final: "The final: {a} {score} {b} ({how}).", champion: "{name} won the final.", toPlay: "The final is still to be played.",
|
|
426
|
-
},
|
|
427
417
|
replay: {
|
|
428
418
|
title: "Replay, {time}", objects: "{n} tracked objects", objectsOne: "{n} tracked object", events: "{n} events", eventsOne: "{n} event", players: "Players", others: "Ball, puck and officials", trail: "Trail of the last {s} seconds", numbers: "Shirt numbers", eventLines: "Passes and shots",
|
|
429
419
|
home: "home", away: "away", ball: "ball", puck: "puck", official: "official", pass: "Pass", shot: "Shot", goal: "Goal", whistle: "Whistle",
|
|
@@ -435,13 +425,14 @@ export const KYOGIJO_STRINGS = {
|
|
|
435
425
|
},
|
|
436
426
|
turn: {
|
|
437
427
|
region: "3D view", group: "Viewpoint",
|
|
438
|
-
keys: "A 3D view you can turn. Drag, or use the arrow keys, to turn and tilt it; plus and minus zoom; 1 to 4 pick a viewpoint; 0 or Home puts it back. Pinch, or hold Ctrl and scroll, to zoom.",
|
|
428
|
+
keys: "A 3D view you can turn. Drag, or use the arrow keys, to turn and tilt it; plus and minus zoom; 1 to 4 pick a viewpoint; 0 or Home puts it back; Space starts and stops the auto-turn. Pinch, or hold Ctrl and scroll, to zoom.",
|
|
439
429
|
overhead: "Overhead", broadcast: "Broadcast", end: "End-on", corner: "Low corner",
|
|
440
430
|
reset: "Reset the view", turnLeft: "Turn left", turnRight: "Turn right", raise: "Tip the surface away", lower: "Tip the surface toward you", zoomIn: "Zoom in", zoomOut: "Zoom out",
|
|
431
|
+
play: "Auto-turn", playOn: "Start the auto-turn", playOff: "Pause the auto-turn", announcePlay: "Auto-turn on", announcePause: "Auto-turn paused",
|
|
441
432
|
announce: "{name} view", announceAngle: "Turned to {yaw} degrees, seen from {pitch} degrees above the floor.",
|
|
442
433
|
flat: "This browser cannot draw the 3D view, so the flat drawing is shown.",
|
|
443
434
|
standing: "Standing on it, in the 3D view: {list}.", item: "{name} {h}", itemSag: "{name} {h} at the posts, {low} at the middle",
|
|
444
|
-
parts: { scoreboard: "scoreboard (lower edge)", net: "net", antennae: "antennae", goalposts: "goal posts", netposts: "net posts", hoop: "baskets", goal: "goals", boards: "boards and glass", stumps: "stumps", pylons: "pylons", flags: "corner flags", fence: "fence", backstop: "backstop", "foul-poles": "foul poles", "table-legs": "table top", walls: "walls", "starting-blocks": "starting blocks", "backstroke-flags": "backstroke flags", "false-start-rope": "false start rope", springboards: "springboards", platforms: "platforms", "judges-stand": "judges' stand", hurdles: "hurdles", steeplechase: "steeplechase barriers", "high-jump": "high jump uprights and bar", "pole-vault": "pole vault uprights and bar", cage: "discus and hammer cage", padding: "padding", "rink-boards": "boards", mound: "clay mound", azuchi: "azuchi", targets: "targets" },
|
|
435
|
+
parts: { scoreboard: "scoreboard (lower edge)", net: "net", antennae: "antennae", goalposts: "goal posts", netposts: "net posts", hoop: "baskets", goal: "goals", boards: "boards and glass", stumps: "stumps", pylons: "pylons", flags: "corner flags", fence: "fence", backstop: "backstop", "foul-poles": "foul poles", "table-legs": "table top", walls: "walls", "starting-blocks": "starting blocks", "backstroke-flags": "backstroke flags", "false-start-rope": "false start rope", springboards: "springboards", platforms: "platforms", "judges-stand": "judges' stand", hurdles: "hurdles", steeplechase: "steeplechase barriers", "high-jump": "high jump uprights and bar", "pole-vault": "pole vault uprights and bar", cage: "discus and hammer cage", padding: "padding", "rink-boards": "boards", mound: "clay mound", azuchi: "azuchi", targets: "targets", stands: "stands", "wall-seats": "seats on top of the wall", roof: "roof", gallery: "gallery", dais: "dais", banner: "banner", shrine: "shrine", "mat-edge": "mat thickness" },
|
|
445
436
|
},
|
|
446
437
|
rules: {
|
|
447
438
|
"defensive-zone": "Defensive zone",
|
|
@@ -959,16 +950,6 @@ export const KYOGIJO_STRINGS = {
|
|
|
959
950
|
},
|
|
960
951
|
},
|
|
961
952
|
grid: { title: "図のグリッド({n}枚)", drawings: "図({n}枚):{list}。", key: "凡例:{list}。", cell: "{total}枚中{n}枚目の図", listSep: ";" },
|
|
962
|
-
road: {
|
|
963
|
-
title: "決勝への道", vs: "対", group: "グループステージ",
|
|
964
|
-
rounds: { "round-of-32": "ラウンド32", "round-of-16": "ラウンド16", "quarter-final": "準々決勝", "semi-final": "準決勝", final: "決勝" },
|
|
965
|
-
ft: "90分", aet: "延長", pens: "PK {a}-{b}", won: "勝ち", lost: "負け", drew: "引き分け",
|
|
966
|
-
tableTeam: "チーム", tableRound: "ラウンド", tableOpponent: "対戦相手", tableScore: "スコア", tableDecided: "決着", tableResult: "結果",
|
|
967
|
-
caption: "{a}と{b}:決勝までの全試合。スコアは「チーム」列のチームの得点を先に書いています。",
|
|
968
|
-
name: "{a}と{b}:{title}",
|
|
969
|
-
summary: "{a}は決勝までに{an}試合、{b}は{bn}試合を戦いました。",
|
|
970
|
-
final: "決勝は{a} {score} {b}({how})でした。", champion: "{name}が優勝しました。", toPlay: "決勝はまだ行われていません。",
|
|
971
|
-
},
|
|
972
953
|
replay: {
|
|
973
954
|
title: "リプレイ(再生時間{time})", objects: "追跡対象は{n}個", objectsOne: "追跡対象は{n}個", events: "イベント{n}件", eventsOne: "イベント{n}件", players: "選手", others: "ボール・パック・審判", trail: "直近{s}秒の軌跡", numbers: "背番号", eventLines: "パスとシュート",
|
|
974
955
|
home: "ホーム", away: "アウェイ", ball: "ボール", puck: "パック", official: "審判", pass: "パス", shot: "シュート", goal: "ゴール", whistle: "ホイッスル",
|
|
@@ -980,13 +961,14 @@ export const KYOGIJO_STRINGS = {
|
|
|
980
961
|
},
|
|
981
962
|
turn: {
|
|
982
963
|
region: "3D表示", group: "視点",
|
|
983
|
-
keys: "回して見られる3D表示です。ドラッグするか矢印キーで回転と傾きを変え、プラスとマイナスのキーで拡大と縮小、1から4のキーで視点を選び、0キーまたはHome
|
|
964
|
+
keys: "回して見られる3D表示です。ドラッグするか矢印キーで回転と傾きを変え、プラスとマイナスのキーで拡大と縮小、1から4のキーで視点を選び、0キーまたはHomeキーで元に戻し、スペースキーで自動回転を始めたり止めたりします。ピンチ操作、またはCtrlキーを押しながらのスクロールでも拡大・縮小できます。",
|
|
984
965
|
overhead: "真上", broadcast: "中継カメラ", end: "エンド側から", corner: "低い角度から",
|
|
985
966
|
reset: "元に戻す", turnLeft: "左へ回す", turnRight: "右へ回す", raise: "床面を奥へ傾ける", lower: "床面を手前へ傾ける", zoomIn: "拡大", zoomOut: "縮小",
|
|
967
|
+
play: "自動回転", playOn: "自動回転を始める", playOff: "自動回転を一時停止する", announcePlay: "自動回転を始めました", announcePause: "自動回転を一時停止しました",
|
|
986
968
|
announce: "{name}の視点", announceAngle: "向きは{yaw}度、見下ろす角度は{pitch}度です。",
|
|
987
969
|
flat: "このブラウザーでは3D表示ができないため、平面の図を表示しています。",
|
|
988
970
|
standing: "3D表示で立って見えるもの:{list}。", item: "{name} {h}", itemSag: "{name} 支柱の位置で{h}(中央は{low})",
|
|
989
|
-
parts: { scoreboard: "スコアボードの下端", net: "ネット", antennae: "アンテナ", goalposts: "ゴールポスト", netposts: "支柱", hoop: "バスケットゴール", goal: "ゴール", boards: "ボードとガラス", stumps: "ウィケットのスタンプ", pylons: "パイロン", flags: "コーナーフラッグ", fence: "外野フェンス", backstop: "バックネット", "foul-poles": "ファウルポール", "table-legs": "天板", walls: "壁", "starting-blocks": "スタート台", "backstroke-flags": "背泳ぎ用フラッグ", "false-start-rope": "フォルススタートロープ", springboards: "飛板", platforms: "固定台", "judges-stand": "ジャッジ台", hurdles: "ハードル", steeplechase: "障害物", "high-jump": "走高跳の支柱とバー", "pole-vault": "棒高跳の支柱とバー", cage: "円盤投・ハンマー投の囲い", padding: "防護マット", "rink-boards": "フェンス", mound: "土の台", azuchi: "安土", targets: "的" },
|
|
971
|
+
parts: { scoreboard: "スコアボードの下端", net: "ネット", antennae: "アンテナ", goalposts: "ゴールポスト", netposts: "支柱", hoop: "バスケットゴール", goal: "ゴール", boards: "ボードとガラス", stumps: "ウィケットのスタンプ", pylons: "パイロン", flags: "コーナーフラッグ", fence: "外野フェンス", backstop: "バックネット", "foul-poles": "ファウルポール", "table-legs": "天板", walls: "壁", "starting-blocks": "スタート台", "backstroke-flags": "背泳ぎ用フラッグ", "false-start-rope": "フォルススタートロープ", springboards: "飛板", platforms: "固定台", "judges-stand": "ジャッジ台", hurdles: "ハードル", steeplechase: "障害物", "high-jump": "走高跳の支柱とバー", "pole-vault": "棒高跳の支柱とバー", cage: "円盤投・ハンマー投の囲い", padding: "防護マット", "rink-boards": "フェンス", mound: "土の台", azuchi: "安土", targets: "的", stands: "スタンド", "wall-seats": "壁の上の観客席", roof: "屋根", gallery: "見学席", dais: "上座の台", banner: "垂れ幕", shrine: "神棚", "mat-edge": "畳の厚み" },
|
|
990
972
|
},
|
|
991
973
|
rules: {
|
|
992
974
|
"defensive-zone": "ディフェンディングゾーン",
|
package/dist/style.js
CHANGED
|
@@ -12,7 +12,6 @@ import { KYOGIJO_LOOK_STYLE } from "./look.js";
|
|
|
12
12
|
import { KYOGIJO_MARK_STYLE } from "./mark.js";
|
|
13
13
|
import { KYOGIJO_PAGEANT_MOTION, KYOGIJO_PAGEANT_STYLE } from "./pageant.style.js";
|
|
14
14
|
import { KYOGIJO_POOL_STYLE } from "./pool.style.js";
|
|
15
|
-
import { KYOGIJO_ROAD_STYLE } from "./road.style.js";
|
|
16
15
|
import { KYOGIJO_SITUATION_STYLE } from "./situation.style.js";
|
|
17
16
|
import { KYOGIJO_SPECIAL_STYLE } from "./special.style.js";
|
|
18
17
|
/**
|
|
@@ -191,4 +190,4 @@ export const KYOGIJO_NOTE_STYLE = `
|
|
|
191
190
|
.kyogijo .ky-an-ar{stroke:var(--c);fill:none}
|
|
192
191
|
.kyogijo .ky-an-hd{fill:var(--c)}`.trim();
|
|
193
192
|
/** Every rule of the package, for a page that draws with `style: "none"` and supplies the stylesheet itself. */
|
|
194
|
-
export const KYOGIJO_STYLE = `${KYOGIJO_BASE_STYLE}\n${KYOGIJO_HEAT_STYLE}\n${KYOGIJO_TEAM_STYLE}\n${KYOGIJO_CURLING_STYLE}\n${KYOGIJO_FOLD_STYLE}\n${KYOGIJO_WALLS_STYLE}\n${KYOGIJO_COURTS_STYLE}\n${KYOGIJO_FIELDS_STYLE}\n${KYOGIJO_POOL_STYLE}\n${KYOGIJO_ATHLETICS_STYLE}\n${KYOGIJO_SKATING_STYLE}\n${KYOGIJO_BUDO_STYLE}\n${KYOGIJO_LOOK_STYLE}\n${KYOGIJO_HARDWOOD_STYLE}\n${KYOGIJO_TRACK_STYLE}\n${KYOGIJO_FEATURE_STYLE}\n${KYOGIJO_NOTE_STYLE}\n${KYOGIJO_SPECIAL_STYLE}\n${KYOGIJO_BACKGROUND_STYLE}\n${KYOGIJO_CROWD_STYLE}\n${KYOGIJO_GRID_STYLE}\n${KYOGIJO_MARK_STYLE}\n${KYOGIJO_PAGEANT_STYLE}\n${KYOGIJO_PAGEANT_MOTION}\n${KYOGIJO_SITUATION_STYLE}
|
|
193
|
+
export const KYOGIJO_STYLE = `${KYOGIJO_BASE_STYLE}\n${KYOGIJO_HEAT_STYLE}\n${KYOGIJO_TEAM_STYLE}\n${KYOGIJO_CURLING_STYLE}\n${KYOGIJO_FOLD_STYLE}\n${KYOGIJO_WALLS_STYLE}\n${KYOGIJO_COURTS_STYLE}\n${KYOGIJO_FIELDS_STYLE}\n${KYOGIJO_POOL_STYLE}\n${KYOGIJO_ATHLETICS_STYLE}\n${KYOGIJO_SKATING_STYLE}\n${KYOGIJO_BUDO_STYLE}\n${KYOGIJO_LOOK_STYLE}\n${KYOGIJO_HARDWOOD_STYLE}\n${KYOGIJO_TRACK_STYLE}\n${KYOGIJO_FEATURE_STYLE}\n${KYOGIJO_NOTE_STYLE}\n${KYOGIJO_SPECIAL_STYLE}\n${KYOGIJO_BACKGROUND_STYLE}\n${KYOGIJO_CROWD_STYLE}\n${KYOGIJO_GRID_STYLE}\n${KYOGIJO_MARK_STYLE}\n${KYOGIJO_PAGEANT_STYLE}\n${KYOGIJO_PAGEANT_MOTION}\n${KYOGIJO_SITUATION_STYLE}`;
|
package/dist/surfaces/budo.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// A budō surface lying wide, from its plan (budo/plan.ts): the floor and the free zone, the mats in their tones with their heri and their seams, the walls, the clay and the straw of a dohyō, the tape,
|
|
2
2
|
// the targets. The plan is in metres; the drawing is in feet, as every surface lies, so the whole is drawn inside a group that scales metres to feet and moves the surface's box to the origin.
|
|
3
|
-
import { el } from "../format.js";
|
|
3
|
+
import { el, num } from "../format.js";
|
|
4
|
+
import { floorTiles } from "../hardwood.js";
|
|
4
5
|
import { areaD, marks, strokes } from "./field.js";
|
|
5
6
|
import { atEnds, edges, ft, quarterTurn } from "./surface.js";
|
|
6
7
|
/** Feet in a metre. */
|
|
7
8
|
export const K = 1 / 0.3048;
|
|
9
|
+
/** The hardwood of a dojo's surround, laid as the basketball floor is (`hardwood.ts`): strip boards of 0.3 ft, each with a tone of its own and a little grain, seams that are only just there. */
|
|
10
|
+
const SURROUND_WOOD = { seed: 11, fine: true, board: 0.3, stain: 0, sheen: 0, hoops: false, bench: false };
|
|
8
11
|
const feetBox = (b, ox, oy) => edges((b.x0 - ox) * K, (b.y0 - oy) * K, (b.x1 - ox) * K, (b.y1 - oy) * K);
|
|
9
12
|
/** A plan's named range in feet, as a surface lists them. */
|
|
10
13
|
function rangeOf(r, ox, oy) {
|
|
@@ -28,7 +31,7 @@ export function budoSurface(o, plan, margin) {
|
|
|
28
31
|
const weave = full && plan.texture && pieces.length > 0;
|
|
29
32
|
const stripe = (at, colour, opacity, width) => el("stop", { offset: at, "stop-color": colour, "stop-opacity": 0 }) + el("stop", { offset: at, "stop-color": colour, "stop-opacity": opacity }) + el("stop", { offset: at + width, "stop-color": colour, "stop-opacity": opacity }) + el("stop", { offset: at + width, "stop-color": colour, "stop-opacity": 0 });
|
|
30
33
|
const woven = () => {
|
|
31
|
-
defs += el("linearGradient", { id: `${o.id}-weave`, x1: 0, y1: 0, x2: 0, y2: 0.1, gradientUnits: "userSpaceOnUse", spreadMethod: "repeat" }, stripe(0.1, "#000000", 0.
|
|
34
|
+
defs += el("linearGradient", { id: `${o.id}-weave`, x1: 0, y1: 0, x2: 0, y2: 0.1, gradientUnits: "userSpaceOnUse", spreadMethod: "repeat" }, stripe(0.1, "#000000", 0.03, 0.22) + stripe(0.52, "#000000", 0.015, 0.16));
|
|
32
35
|
const rect = (p) => `M${p.x0} ${p.y0}H${p.x1}V${p.y1}H${p.x0}Z`;
|
|
33
36
|
// A mat that lies across is drawn in a group turned a quarter, with its corners turned back, so that its ridges run along it.
|
|
34
37
|
const turned = (p) => `M${p.y0} ${-p.x0}H${p.y1}V${-p.x1}H${p.y0}Z`;
|
|
@@ -43,6 +46,19 @@ export function budoSurface(o, plan, margin) {
|
|
|
43
46
|
out += el("path", { class: "ky-bud-edge", d: pieces.map(rect).join(""), fill: "none" });
|
|
44
47
|
return out;
|
|
45
48
|
};
|
|
49
|
+
// The surround is polished hardwood: the boards (under) and their seams (over) as two tiles of the basketball floor's code, in feet and turned to metres, and a warm satin sheen in a few
|
|
50
|
+
// broad diagonal glints over them. Drawn only at full detail.
|
|
51
|
+
let polished = false;
|
|
52
|
+
const polish = (d) => {
|
|
53
|
+
const tiles = floorTiles(SURROUND_WOOD);
|
|
54
|
+
const tile = (suffix, body) => el("pattern", { id: `${o.id}-wood-${suffix}`, width: 96, height: num(tiles.height), patternUnits: "userSpaceOnUse", patternTransform: `scale(${(1 / K).toFixed(6)})` }, body);
|
|
55
|
+
const b = plan.box;
|
|
56
|
+
const glint = (at, w, a) => el("stop", { offset: at - w, "stop-color": "#fff1cf", "stop-opacity": 0 }) + el("stop", { offset: at, "stop-color": "#fff1cf", "stop-opacity": a }) + el("stop", { offset: at + w, "stop-color": "#fff1cf", "stop-opacity": 0 });
|
|
57
|
+
defs += tile("a", tiles.under) + tile("b", tiles.over) + el("linearGradient", { id: `${o.id}-wood-s`, gradientUnits: "userSpaceOnUse", x1: b.x0, y1: b.y0, x2: b.x1, y2: b.y1 }, glint(0.22, 0.06, 0.1) + glint(0.5, 0.08, 0.13) + glint(0.78, 0.05, 0.08));
|
|
58
|
+
const layer = (suffix, opacity) => el("path", { class: "ky-bud-wood", d, "fill-rule": "evenodd", fill: `url(#${o.id}-wood-${suffix})`, opacity });
|
|
59
|
+
// The boards are meant to be seen only when looked for: the tones and the seams are laid at half strength.
|
|
60
|
+
return layer("a", 0.5) + layer("b", 0.45) + layer("s");
|
|
61
|
+
};
|
|
46
62
|
let pending = false;
|
|
47
63
|
let wove = false;
|
|
48
64
|
for (const a of plan.areas) {
|
|
@@ -54,6 +70,10 @@ export function budoSurface(o, plan, margin) {
|
|
|
54
70
|
if (tone)
|
|
55
71
|
pending = true;
|
|
56
72
|
ground += el("path", { class: ft(o, a.feature, a.cls), d: areaD(a), "fill-rule": a.evenodd === true ? "evenodd" : undefined });
|
|
73
|
+
if (full && a.id === "surround" && !polished) {
|
|
74
|
+
polished = true;
|
|
75
|
+
ground += polish(areaD(a));
|
|
76
|
+
}
|
|
57
77
|
}
|
|
58
78
|
if (weave && !wove)
|
|
59
79
|
ground += woven();
|
package/dist/turn-entry.d.ts
CHANGED
|
@@ -9,4 +9,6 @@ export { CURLING_PRESETS, LONG_PRESETS, NET_PRESETS, PITCH_MAX, STEP, TURN_DEFAU
|
|
|
9
9
|
export type { Box3, Mat4, Placement, TurnPreset, TurnToward, TurnView } from "./turn.camera.ts";
|
|
10
10
|
export { describeUprights, heightUnit, planesOf, uprightsFor } from "./uprights.ts";
|
|
11
11
|
export type { UprightOptions, Uprights } from "./uprights.ts";
|
|
12
|
+
export { ROOF } from "./venue.ts";
|
|
13
|
+
export type { Venue, VenueBuild, VenueSettings } from "./venue.ts";
|
|
12
14
|
export type { Plane, PartKind, Upright, UprightKind, V3 } from "./turn.kit.ts";
|
package/dist/turn-entry.js
CHANGED
|
@@ -5,3 +5,4 @@ export { layoutOf, planeMarkup, planeMatrix, turnMarkup, turnMarkupOf } from "./
|
|
|
5
5
|
export { KYOGIJO_TURN_STYLE } from "./turn.style.js";
|
|
6
6
|
export { CURLING_PRESETS, LONG_PRESETS, NET_PRESETS, PITCH_MAX, STEP, TURN_DEFAULT, TURN_PRESETS, TURN_PRESET_NAMES, ZOOM_MAX, ZOOM_MIN, cameraMatrix, clampView, depthOf, drag, eyeDistance, fit, matrix3d, multiply, nudge, presetOf, presetView, presetsFor, project, step } from "./turn.camera.js";
|
|
7
7
|
export { describeUprights, heightUnit, planesOf, uprightsFor } from "./uprights.js";
|
|
8
|
+
export { ROOF } from "./venue.js";
|
package/dist/turn.dom.d.ts
CHANGED
|
@@ -15,6 +15,14 @@ export interface KyogijoTurn {
|
|
|
15
15
|
reset(): void;
|
|
16
16
|
/** Draw again with new options (a score that moved, a look that changed), keeping the view. */
|
|
17
17
|
update(options: SurfaceOptions | ScoreOptions): void;
|
|
18
|
+
/** Whether the auto-turn is running. */
|
|
19
|
+
readonly playing: boolean;
|
|
20
|
+
/** Start the auto-turn, a slow turn of the whole view. It gives whether it is running (a surface that cannot turn gives `false`). Nothing turns by itself until this, the Play button or Space starts it, unless `autoPlay` asked. */
|
|
21
|
+
play(): boolean;
|
|
22
|
+
/** Stop the auto-turn. */
|
|
23
|
+
pause(): void;
|
|
24
|
+
/** Start the auto-turn if it is stopped and stop it if it is running; it gives whether it is running now. */
|
|
25
|
+
togglePlay(): boolean;
|
|
18
26
|
/** The flat drawing that is the floor, or `null` after `destroy`. */
|
|
19
27
|
svg(): SVGSVGElement | null;
|
|
20
28
|
/** Stop listening and empty the container. */
|
package/dist/turn.dom.js
CHANGED
|
@@ -15,7 +15,7 @@ export function turnSupported(win = typeof window === "undefined" ? undefined :
|
|
|
15
15
|
return false;
|
|
16
16
|
return css.supports("transform", "matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)");
|
|
17
17
|
}
|
|
18
|
-
const KEYS = { ArrowLeft: true, ArrowRight: true, ArrowUp: true, ArrowDown: true, "+": true, "=": true, "-": true, _: true, "0": true, Home: true, "1": true, "2": true, "3": true, "4": true };
|
|
18
|
+
const KEYS = { " ": true, ArrowLeft: true, ArrowRight: true, ArrowUp: true, ArrowDown: true, "+": true, "=": true, "-": true, _: true, "0": true, Home: true, "1": true, "2": true, "3": true, "4": true };
|
|
19
19
|
/** The view part of the way from one to another, `t` from 0 to 1, the turn taken the short way round. */
|
|
20
20
|
const between = (from, to, t) => ({ yaw: from.yaw + (nearest(from.yaw, to.yaw) - from.yaw) * t, pitch: from.pitch + (to.pitch - from.pitch) * t, zoom: from.zoom * Math.pow(to.zoom / from.zoom, t) });
|
|
21
21
|
/**
|
|
@@ -48,6 +48,10 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
48
48
|
set: () => undefined,
|
|
49
49
|
preset: () => undefined,
|
|
50
50
|
reset: () => undefined,
|
|
51
|
+
playing: false,
|
|
52
|
+
play: () => false,
|
|
53
|
+
pause: () => undefined,
|
|
54
|
+
togglePlay: () => false,
|
|
51
55
|
update: (next) => {
|
|
52
56
|
model = buildTurn(next, settings);
|
|
53
57
|
flat(next);
|
|
@@ -70,6 +74,12 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
70
74
|
let opening = model.view;
|
|
71
75
|
let flight;
|
|
72
76
|
let spoken;
|
|
77
|
+
// The auto-turn: whether it is on, the frame that will advance it, the time of the last one, and whether it has moved the view since the page was last told.
|
|
78
|
+
let playing = false;
|
|
79
|
+
let tickFrame;
|
|
80
|
+
let lastTick;
|
|
81
|
+
let advanced = false;
|
|
82
|
+
const speed = typeof settings.speed === "number" && Number.isFinite(settings.speed) ? settings.speed : 12;
|
|
73
83
|
const calm = () => settings.motion === "none" || (settings.motion !== "smooth" && media?.matches === true);
|
|
74
84
|
// The elements, floor first, and what was written to each, so that only a change is written.
|
|
75
85
|
let elements = [];
|
|
@@ -84,6 +94,18 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
84
94
|
};
|
|
85
95
|
gather();
|
|
86
96
|
const buttons = () => root.querySelectorAll("button[data-preset]");
|
|
97
|
+
/** The Play button says what it is and what it does: pressed while the view turns. */
|
|
98
|
+
const syncPlay = () => {
|
|
99
|
+
const button = root.querySelector("button[data-act=play]");
|
|
100
|
+
if (button === null)
|
|
101
|
+
return;
|
|
102
|
+
const words = turnWords(model);
|
|
103
|
+
button.setAttribute("aria-pressed", String(playing));
|
|
104
|
+
button.title = playing ? words.playOff : words.playOn;
|
|
105
|
+
const glyph = button.querySelector("[data-glyph]");
|
|
106
|
+
if (glyph !== null)
|
|
107
|
+
glyph.textContent = playing ? "❚❚" : "▶";
|
|
108
|
+
};
|
|
87
109
|
/** Put a view on the screen. */
|
|
88
110
|
const paint = (now) => {
|
|
89
111
|
const width = stage.clientWidth || 960;
|
|
@@ -155,7 +177,10 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
155
177
|
const angles = () => turnWords(model).announceAngle.replace("{yaw}", String(Math.round(((view.yaw % 360) + 360) % 360))).replace("{pitch}", String(Math.round(90 - view.pitch)));
|
|
156
178
|
const changed = () => settings.onChange?.(view, presetOf(view, sport()));
|
|
157
179
|
/** Move to a view the controls asked for: glide, say where it is, tell the page. */
|
|
158
|
-
const go = (next, ms, speak = "angle") => {
|
|
180
|
+
const go = (next, ms, speak = "angle", keepPlaying = false) => {
|
|
181
|
+
// Anything the reader (or the page) asks of the view takes it over from the auto-turn, but a zoom, which does not turn it.
|
|
182
|
+
if (!keepPlaying)
|
|
183
|
+
setPlaying(false, true);
|
|
159
184
|
// A turn takes the short way round, even from 170 degrees to -170.
|
|
160
185
|
show(clampView({ ...next, yaw: nearest(view.yaw, next.yaw) }), ms);
|
|
161
186
|
if (speak === "preset") {
|
|
@@ -172,6 +197,82 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
172
197
|
go(opening, 560, "none");
|
|
173
198
|
say(turnWords(model).reset);
|
|
174
199
|
};
|
|
200
|
+
// ---- The auto-turn: a trophy case's slow turn. It runs only when asked, holds while the pointer holds the view, and does nothing while the page is hidden. ----
|
|
201
|
+
const hidden = () => doc.hidden === true;
|
|
202
|
+
const stopTick = () => {
|
|
203
|
+
if (tickFrame !== undefined)
|
|
204
|
+
win?.cancelAnimationFrame(tickFrame);
|
|
205
|
+
tickFrame = undefined;
|
|
206
|
+
lastTick = undefined;
|
|
207
|
+
};
|
|
208
|
+
const tick = (stamp) => {
|
|
209
|
+
tickFrame = undefined;
|
|
210
|
+
if (!playing || !alive)
|
|
211
|
+
return;
|
|
212
|
+
// Hidden, off the screen or held: the loop ends here, and the visibility change, the scroll back or the pointer's release starts it again.
|
|
213
|
+
if (hidden() || !onScreen || down.size > 0) {
|
|
214
|
+
lastTick = undefined;
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// About thirty frames a second are plenty for a slow turn, and every plane is written at each.
|
|
218
|
+
if (lastTick !== undefined && stamp - lastTick < 30) {
|
|
219
|
+
loop();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const dt = lastTick === undefined ? 0 : Math.min(0.1, (stamp - lastTick) / 1000);
|
|
223
|
+
lastTick = stamp;
|
|
224
|
+
if (dt > 0) {
|
|
225
|
+
stop();
|
|
226
|
+
view = clampView({ ...view, yaw: view.yaw - speed * dt });
|
|
227
|
+
shown = view;
|
|
228
|
+
advanced = true;
|
|
229
|
+
paint(shown);
|
|
230
|
+
label();
|
|
231
|
+
}
|
|
232
|
+
loop();
|
|
233
|
+
};
|
|
234
|
+
const loop = () => {
|
|
235
|
+
if (tickFrame === undefined && playing && alive && win !== null)
|
|
236
|
+
tickFrame = win.requestAnimationFrame(tick);
|
|
237
|
+
};
|
|
238
|
+
/** Start or stop the auto-turn. `quiet` leaves the live region alone (a key or a drag stopped it, and says its own thing). */
|
|
239
|
+
const setPlaying = (next, quiet = false) => {
|
|
240
|
+
if (playing === next)
|
|
241
|
+
return;
|
|
242
|
+
playing = next;
|
|
243
|
+
stopTick();
|
|
244
|
+
syncPlay();
|
|
245
|
+
if (next)
|
|
246
|
+
loop();
|
|
247
|
+
else if (advanced) {
|
|
248
|
+
// The page is told where the view ended up, once, not at every frame.
|
|
249
|
+
advanced = false;
|
|
250
|
+
changed();
|
|
251
|
+
}
|
|
252
|
+
if (!quiet)
|
|
253
|
+
say(next ? turnWords(model).announcePlay : turnWords(model).announcePause);
|
|
254
|
+
settings.onPlayChange?.(next);
|
|
255
|
+
};
|
|
256
|
+
// A view scrolled out of sight does not turn.
|
|
257
|
+
let onScreen = true;
|
|
258
|
+
let seen;
|
|
259
|
+
if (typeof IntersectionObserver === "function") {
|
|
260
|
+
seen = new IntersectionObserver((entries) => {
|
|
261
|
+
onScreen = entries[entries.length - 1]?.isIntersecting !== false;
|
|
262
|
+
if (onScreen && playing) {
|
|
263
|
+
lastTick = undefined;
|
|
264
|
+
loop();
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
seen.observe(stage);
|
|
268
|
+
}
|
|
269
|
+
const onVisible = () => {
|
|
270
|
+
if (playing && !hidden()) {
|
|
271
|
+
lastTick = undefined;
|
|
272
|
+
loop();
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
doc.addEventListener("visibilitychange", onVisible);
|
|
175
276
|
// ---- Buttons. ----
|
|
176
277
|
const onClick = (event) => {
|
|
177
278
|
const target = event.target?.closest("button");
|
|
@@ -187,8 +288,9 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
187
288
|
case "turn-right": return go(nudge(view, "right", big ? STEP.yawBig : STEP.yaw * 2), 180);
|
|
188
289
|
case "raise": return go(nudge(view, "up", big ? STEP.pitchBig : STEP.pitch * 2), 180);
|
|
189
290
|
case "lower": return go(nudge(view, "down", big ? STEP.pitchBig : STEP.pitch * 2), 180);
|
|
190
|
-
case "zoom-in": return go(step(view, { zoom: STEP.zoom }), 180, "none");
|
|
191
|
-
case "zoom-out": return go(step(view, { zoom: 1 / STEP.zoom }), 180, "none");
|
|
291
|
+
case "zoom-in": return go(step(view, { zoom: STEP.zoom }), 180, "none", true);
|
|
292
|
+
case "zoom-out": return go(step(view, { zoom: 1 / STEP.zoom }), 180, "none", true);
|
|
293
|
+
case "play": return void setPlaying(!playing);
|
|
192
294
|
case "reset": return toOpening();
|
|
193
295
|
default:
|
|
194
296
|
}
|
|
@@ -209,9 +311,10 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
209
311
|
case "ArrowUp": return go(nudge(view, "up", pitch), 120);
|
|
210
312
|
case "ArrowDown": return go(nudge(view, "down", pitch), 120);
|
|
211
313
|
case "+":
|
|
212
|
-
case "=": return go(step(view, { zoom: STEP.zoom }), 120, "none");
|
|
314
|
+
case "=": return go(step(view, { zoom: STEP.zoom }), 120, "none", true);
|
|
213
315
|
case "-":
|
|
214
|
-
case "_": return go(step(view, { zoom: 1 / STEP.zoom }), 120, "none");
|
|
316
|
+
case "_": return go(step(view, { zoom: 1 / STEP.zoom }), 120, "none", true);
|
|
317
|
+
case " ": return void setPlaying(!playing);
|
|
215
318
|
case "0":
|
|
216
319
|
case "Home": return toOpening();
|
|
217
320
|
default: toPreset(TURN_PRESET_NAMES[Number(event.key) - 1]);
|
|
@@ -240,6 +343,8 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
240
343
|
}
|
|
241
344
|
moved = false;
|
|
242
345
|
grab();
|
|
346
|
+
// The auto-turn holds while the pointer does.
|
|
347
|
+
stopTick();
|
|
243
348
|
if (down.size === 1)
|
|
244
349
|
root.setAttribute("data-dragging", "");
|
|
245
350
|
if (down.size === 2) {
|
|
@@ -273,6 +378,8 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
273
378
|
if (down.size === 0) {
|
|
274
379
|
root.removeAttribute("data-dragging");
|
|
275
380
|
label();
|
|
381
|
+
if (playing)
|
|
382
|
+
loop();
|
|
276
383
|
if (moved) {
|
|
277
384
|
say(angles(), 450);
|
|
278
385
|
changed();
|
|
@@ -309,6 +416,9 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
309
416
|
observer = new ResizeObserver(() => alive && paint(shown));
|
|
310
417
|
observer.observe(stage);
|
|
311
418
|
}
|
|
419
|
+
// Nothing moves until the reader asks, unless the page did: `autoPlay` starts it, but not for a reader who prefers reduced motion (`"force"` does).
|
|
420
|
+
if (settings.autoPlay === "force" || (settings.autoPlay === true && !calm()))
|
|
421
|
+
setPlaying(true, true);
|
|
312
422
|
return {
|
|
313
423
|
mode: "3d",
|
|
314
424
|
view: () => ({ ...view }),
|
|
@@ -324,7 +434,19 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
324
434
|
view = clampView(view);
|
|
325
435
|
opening = openingView(settings, sport());
|
|
326
436
|
const layout = layoutOf(model, shown, stage.clientWidth || 960, stage.clientHeight || 600, settings.lens);
|
|
327
|
-
root.querySelector(".ky-turn-world")
|
|
437
|
+
const world = root.querySelector(".ky-turn-world");
|
|
438
|
+
world.innerHTML = worldMarkup(model, layout);
|
|
439
|
+
// The look the floor is painted in (and the theme) are attributes of the world.
|
|
440
|
+
for (const name of ["data-sport", "data-look", "data-theme"])
|
|
441
|
+
world.removeAttribute(name);
|
|
442
|
+
world.className = model.look === undefined ? "ky-turn-world" : "ky-turn-world kyogijo";
|
|
443
|
+
if (model.look !== undefined) {
|
|
444
|
+
world.setAttribute("data-sport", model.look.sport);
|
|
445
|
+
world.setAttribute("data-look", model.look.look);
|
|
446
|
+
const forced = model.options.theme;
|
|
447
|
+
if (forced === "light" || forced === "dark")
|
|
448
|
+
world.setAttribute("data-theme", forced);
|
|
449
|
+
}
|
|
328
450
|
gather();
|
|
329
451
|
stage.setAttribute("aria-label", model.title);
|
|
330
452
|
root.querySelector(".ky-turn-help").textContent = `${turnWords(model).keys}${model.standing === "" ? "" : ` ${model.standing}`}`;
|
|
@@ -335,16 +457,33 @@ export function mountKyogijoTurn(host, options, settings = {}) {
|
|
|
335
457
|
root.removeAttribute("data-theme");
|
|
336
458
|
const controls = root.querySelector(".ky-turn-controls");
|
|
337
459
|
if (controls !== null)
|
|
338
|
-
controls.outerHTML = controlsMarkup(model, view);
|
|
460
|
+
controls.outerHTML = controlsMarkup(model, view, playing);
|
|
339
461
|
paint(shown);
|
|
340
462
|
label();
|
|
341
463
|
},
|
|
464
|
+
get playing() {
|
|
465
|
+
return playing;
|
|
466
|
+
},
|
|
467
|
+
play() {
|
|
468
|
+
setPlaying(true);
|
|
469
|
+
return playing;
|
|
470
|
+
},
|
|
471
|
+
pause() {
|
|
472
|
+
setPlaying(false);
|
|
473
|
+
},
|
|
474
|
+
togglePlay() {
|
|
475
|
+
setPlaying(!playing);
|
|
476
|
+
return playing;
|
|
477
|
+
},
|
|
342
478
|
svg: () => (alive ? root.querySelector(".ky-turn-floor svg.kyogijo") : null),
|
|
343
479
|
destroy() {
|
|
344
480
|
if (!alive)
|
|
345
481
|
return;
|
|
346
482
|
alive = false;
|
|
347
483
|
stop();
|
|
484
|
+
stopTick();
|
|
485
|
+
seen?.disconnect();
|
|
486
|
+
doc.removeEventListener("visibilitychange", onVisible);
|
|
348
487
|
clearTimeout(spoken);
|
|
349
488
|
observer?.disconnect();
|
|
350
489
|
host.replaceChildren();
|
package/dist/turn.kit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** A point or a direction: x, y, z in feet. */
|
|
2
2
|
export type V3 = readonly [number, number, number];
|
|
3
3
|
/** What a plane is a part of: it is the class of its element (`ky-up-<kind>`) and what a test finds it by. */
|
|
4
|
-
export type PartKind = "post" | "net" | "tape" | "antenna" | "board" | "glass" | "rim" | "stanchion" | "frame" | "goal" | "flag" | "stump" | "leg" | "table" | "pylon" | "wall" | "screen" | "pole" | "ground" | "target";
|
|
4
|
+
export type PartKind = "post" | "net" | "tape" | "antenna" | "board" | "glass" | "rim" | "stanchion" | "frame" | "goal" | "flag" | "stump" | "leg" | "table" | "pylon" | "wall" | "screen" | "pole" | "ground" | "target" | "seats" | "concourse" | "fascia" | "roof" | "banner" | "platform" | "rail" | "matedge" | "shrine";
|
|
5
5
|
/** One flat rectangle. Its own x runs along `u` (its whole length) and its own y along `v`; `o` is the corner both start from. `svg` is what is drawn on it, in feet along `u` and `v`. */
|
|
6
6
|
export interface Plane {
|
|
7
7
|
/** A name that says what it is and where: `net`, `post-left`, `goal-right-back`. */
|
|
@@ -21,9 +21,11 @@ export interface Plane {
|
|
|
21
21
|
* wall. The nearer the eye is to that side, and the lower it is, the more the wall is cut away (see `fadeOf`), so that the court is never hidden behind its own glass.
|
|
22
22
|
*/
|
|
23
23
|
shy?: readonly [number, number];
|
|
24
|
+
/** How much of a `shy` plane is left when it is cut away altogether: 0.08 when missing. A plane that others lie over on the screen (the steps of a gallery) takes less, so that they do not add up to a veil. */
|
|
25
|
+
fadeTo?: number;
|
|
24
26
|
}
|
|
25
27
|
/** What stands on the surface as a thing a reader would name: a net, a basket, a goal, a pair of posts. */
|
|
26
|
-
export type UprightKind = "scoreboard" | "net" | "antennae" | "goalposts" | "netposts" | "hoop" | "goal" | "boards" | "stumps" | "pylons" | "flags" | "fence" | "backstop" | "foul-poles" | "table-legs" | "walls" | "starting-blocks" | "backstroke-flags" | "false-start-rope" | "springboards" | "platforms" | "judges-stand" | "hurdles" | "steeplechase" | "high-jump" | "pole-vault" | "cage" | "padding" | "rink-boards" | "mound" | "azuchi" | "targets";
|
|
28
|
+
export type UprightKind = "scoreboard" | "net" | "antennae" | "goalposts" | "netposts" | "hoop" | "goal" | "boards" | "stumps" | "pylons" | "flags" | "fence" | "backstop" | "foul-poles" | "table-legs" | "walls" | "starting-blocks" | "backstroke-flags" | "false-start-rope" | "springboards" | "platforms" | "judges-stand" | "hurdles" | "steeplechase" | "high-jump" | "pole-vault" | "cage" | "padding" | "rink-boards" | "mound" | "azuchi" | "targets" | "stands" | "wall-seats" | "roof" | "gallery" | "dais" | "banner" | "shrine" | "mat-edge";
|
|
27
29
|
/** A thing that stands on the surface: where, how high, and the planes it is made of. */
|
|
28
30
|
export interface Upright {
|
|
29
31
|
id: string;
|
|
@@ -83,4 +85,4 @@ export declare function shy(p: Plane, centre: readonly [number, number]): Plane;
|
|
|
83
85
|
* How much of a wall is left (1 whole, down to 0.08) at a view: none is cut away unless the wall is on the eye's side of the surface, and then more the lower the eye is, because a wall seen
|
|
84
86
|
* from straight above hides nothing. `yaw` and `pitch` are the view's, in degrees.
|
|
85
87
|
*/
|
|
86
|
-
export declare function fadeOf(p: Pick<Plane, "shy">, yaw: number, pitch: number): number;
|
|
88
|
+
export declare function fadeOf(p: Pick<Plane, "shy" | "fadeTo">, yaw: number, pitch: number): number;
|
package/dist/turn.kit.js
CHANGED
|
@@ -106,5 +106,5 @@ export function fadeOf(p, yaw, pitch) {
|
|
|
106
106
|
const toward = p.shy[0] * Math.sin(a) + p.shy[1] * Math.cos(a);
|
|
107
107
|
const hides = toward * Math.sin((pitch * Math.PI) / 180);
|
|
108
108
|
const t = Math.min(1, Math.max(0, (hides - 0.1) / 0.25));
|
|
109
|
-
return Math.round((1 - 0.
|
|
109
|
+
return Math.round((1 - (1 - (p.fadeTo ?? 0.08)) * t) * 1000) / 1000;
|
|
110
110
|
}
|
package/dist/turn.markup.d.ts
CHANGED
|
@@ -23,10 +23,17 @@ export declare function layoutOf(model: TurnModel, view: TurnView, width: number
|
|
|
23
23
|
export declare function planeMarkup(p: Plane, scale: number, transform: string, stack: number, fade?: number): string;
|
|
24
24
|
/** The floor as an element: the flat drawing, in the pixels of the scene. */
|
|
25
25
|
export declare function floorMarkup(model: TurnModel, transform: string, stack: number): string;
|
|
26
|
+
/** The patterns the venue's planes are drawn with, once, in a box of no size: every plane's SVG reads them by id, and the crowd's colours are on this element. */
|
|
27
|
+
export declare function defsMarkup(model: TurnModel): string;
|
|
28
|
+
/**
|
|
29
|
+
* The attributes of the element the planes stand in. A floor painted in a look (a dojo's mats) gets the drawing's own class, sport and look, so that the stylesheet's rules for the look set
|
|
30
|
+
* its custom properties here too, and the walls and the wood of the room are the colours of the floor. A theme the options force goes with them.
|
|
31
|
+
*/
|
|
32
|
+
export declare function worldAttributes(model: TurnModel): string;
|
|
26
33
|
/** The floor and the planes of a model, laid out. */
|
|
27
34
|
export declare function worldMarkup(model: TurnModel, layout: Layout): string;
|
|
28
35
|
/** The buttons under the view. */
|
|
29
|
-
export declare function controlsMarkup(model: TurnModel, view: TurnView): string;
|
|
36
|
+
export declare function controlsMarkup(model: TurnModel, view: TurnView, playing?: boolean): string;
|
|
30
37
|
/** The size, in pixels, the first view is worked out for. */
|
|
31
38
|
export declare const sizeOf: (settings: TurnSettings) => {
|
|
32
39
|
width: number;
|
package/dist/turn.markup.js
CHANGED
|
@@ -52,12 +52,24 @@ export function floorMarkup(model, transform, stack) {
|
|
|
52
52
|
const vb = model.viewBox;
|
|
53
53
|
return `<div class="ky-turn-floor" style="width:${px(vb.w * model.scale)}px;height:${px(vb.h * model.scale)}px;transform:${transform};z-index:${stack}">${model.floor}</div>`;
|
|
54
54
|
}
|
|
55
|
+
/** The patterns the venue's planes are drawn with, once, in a box of no size: every plane's SVG reads them by id, and the crowd's colours are on this element. */
|
|
56
|
+
export function defsMarkup(model) {
|
|
57
|
+
return model.defs === "" ? "" : `<svg class="ky-turn-defs" xmlns="http://www.w3.org/2000/svg" width="0" height="0"${model.crowdStyle === "" ? "" : ` style="${esc(model.crowdStyle)}"`} aria-hidden="true" focusable="false"><defs>${model.defs}</defs></svg>`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The attributes of the element the planes stand in. A floor painted in a look (a dojo's mats) gets the drawing's own class, sport and look, so that the stylesheet's rules for the look set
|
|
61
|
+
* its custom properties here too, and the walls and the wood of the room are the colours of the floor. A theme the options force goes with them.
|
|
62
|
+
*/
|
|
63
|
+
export function worldAttributes(model) {
|
|
64
|
+
const theme = model.options.theme;
|
|
65
|
+
return model.look === undefined ? 'class="ky-turn-world"' : `class="ky-turn-world kyogijo" data-sport="${esc(model.look.sport)}" data-look="${esc(model.look.look)}"${theme === "light" || theme === "dark" ? ` data-theme="${theme}"` : ""}`;
|
|
66
|
+
}
|
|
55
67
|
/** The floor and the planes of a model, laid out. */
|
|
56
68
|
export function worldMarkup(model, layout) {
|
|
57
|
-
return floorMarkup(model, layout.transforms[0], layout.stack[0]) + model.planes.map((p, i) => planeMarkup(p, model.scale, layout.transforms[i + 1], layout.stack[i + 1], layout.fade[i + 1])).join("");
|
|
69
|
+
return defsMarkup(model) + floorMarkup(model, layout.transforms[0], layout.stack[0]) + model.planes.map((p, i) => planeMarkup(p, model.scale, layout.transforms[i + 1], layout.stack[i + 1], layout.fade[i + 1])).join("");
|
|
58
70
|
}
|
|
59
71
|
/** The buttons under the view. */
|
|
60
|
-
export function controlsMarkup(model, view) {
|
|
72
|
+
export function controlsMarkup(model, view, playing = false) {
|
|
61
73
|
const words = turnWords(model);
|
|
62
74
|
const here = presetOf(view, model.options.sport);
|
|
63
75
|
const presets = TURN_PRESET_NAMES.map((name, i) => `<button type="button" data-preset="${name}" aria-pressed="${here === name}" aria-keyshortcuts="${i + 1}">${esc(words[name])}</button>`).join("");
|
|
@@ -70,7 +82,9 @@ export function controlsMarkup(model, view) {
|
|
|
70
82
|
["zoom-out", "−", words.zoomOut],
|
|
71
83
|
];
|
|
72
84
|
const buttons = tools.map(([act, glyph, label]) => `<button type="button" data-act="${act}" aria-label="${esc(label)}" title="${esc(label)}">${glyph}</button>`).join("");
|
|
73
|
-
|
|
85
|
+
// The auto-turn: a toggle named for what it is, pressed while the view turns; its glyph and tooltip say what pressing it does.
|
|
86
|
+
const play = `<button type="button" data-act="play" data-wide aria-pressed="${playing}" aria-keyshortcuts="Space" title="${esc(playing ? words.playOff : words.playOn)}"><span data-glyph aria-hidden="true">${playing ? "❚❚" : "▶"}</span>${esc(words.play)}</button>`;
|
|
87
|
+
return `<div class="ky-turn-controls"><div class="ky-turn-group" role="group" aria-label="${esc(words.group)}">${presets}</div><div class="ky-turn-group">${buttons}<button type="button" data-act="reset" aria-keyshortcuts="0 Home">${esc(words.reset)}</button>${play}</div></div>`;
|
|
74
88
|
}
|
|
75
89
|
/** The size, in pixels, the first view is worked out for. */
|
|
76
90
|
export const sizeOf = (settings) => settings.size ?? { width: 960, height: 600 };
|
|
@@ -86,7 +100,7 @@ export function turnMarkupOf(model, settings = {}) {
|
|
|
86
100
|
const sport = model.options.sport;
|
|
87
101
|
return (`<div class="ky-turn" id="${esc(model.id)}" data-sport="${esc(String(sport))}" data-mode="3d" data-touch="${settings.touch === "turn" ? "turn" : "scroll"}" data-preset="${presetOf(view, sport) ?? "custom"}"${theme === "light" || theme === "dark" ? ` data-theme="${theme}"` : ""} lang="${model.language}">` +
|
|
88
102
|
sheet +
|
|
89
|
-
`<div class="ky-turn-view" tabindex="0" role="group" aria-roledescription="${esc(words.region)}" aria-label="${esc(model.title)}" aria-describedby="${esc(model.id)}-help" aria-keyshortcuts="ArrowLeft ArrowRight ArrowUp ArrowDown + - 0 1 2 3 4 Home"><div
|
|
103
|
+
`<div class="ky-turn-view" tabindex="0" role="group" aria-roledescription="${esc(words.region)}" aria-label="${esc(model.title)}" aria-describedby="${esc(model.id)}-help" aria-keyshortcuts="ArrowLeft ArrowRight ArrowUp ArrowDown + - 0 1 2 3 4 Home Space"><div ${worldAttributes(model)}>${worldMarkup(model, layout)}</div></div>` +
|
|
90
104
|
`<p class="ky-turn-help" id="${esc(model.id)}-help">${esc(keys)}</p>` +
|
|
91
105
|
(settings.controls === false ? "" : controlsMarkup(model, view)) +
|
|
92
106
|
`<div class="ky-turn-live" role="status" aria-live="polite"></div>` +
|