feat: add contextual heaven loading rituals

This commit is contained in:
leefer
2026-07-23 23:11:51 +08:00
parent d520749252
commit bc7521a591
5 changed files with 728 additions and 23 deletions
+53 -3
View File
@@ -140,6 +140,7 @@ const LIVE_REFRESH_DEFAULT_MS = 10 * 1000;
let qiFieldAnimationFrame = 0;
let qiFieldSoloElement = "";
let heavenPerformanceToken = 0;
let heavenReadingAnimation = null;
let heartHoldTimer = null;
let heartHoldTriggered = false;
let heartHoldStartedAt = 0;
@@ -623,6 +624,7 @@ function bindEvents() {
document.querySelector("#viewHeartReadingButton").addEventListener("click", () => openHeavenReading("heart"));
document.querySelector("#restartHeartButton").addEventListener("click", resetHeartRitual);
document.querySelector("#closeHeavenReadingDialog").addEventListener("click", () => elements.heavenReadingDialog.close());
elements.heavenReadingDialog.addEventListener("close", stopHeavenReadingAnimation);
document.querySelectorAll("[data-heaven-reading-tab]").forEach((button) => {
button.addEventListener("click", () => selectHeavenReadingTab(button.dataset.heavenReadingTab));
});
@@ -3483,6 +3485,44 @@ function heavenReadingMeta(mode = state.heavenReadingMode) {
return HEAVEN_READING_META[mode] || HEAVEN_READING_META.trend;
}
function heavenReadingAnimationData() {
const field = state.heavenSetup?.field || {};
return {
yearPillar: field.pillars?.year || "",
movement: field.movement?.label || "",
sixQi: {
sitian: field.six_qi?.sitian || "",
zaiquan: field.six_qi?.zaiquan || "",
step: number(field.six_qi?.step) || 1,
},
};
}
function syncHeavenReadingAnimation() {
const canvas = document.querySelector("#heavenReadingCanvas");
const shouldRun = state.heavenReadingLoading && state.heavenReadingTab === "current";
if (!canvas || !window.HeavenLoadingCanvas) return;
if (!shouldRun) {
stopHeavenReadingAnimation();
return;
}
if (!heavenReadingAnimation) heavenReadingAnimation = new window.HeavenLoadingCanvas(canvas);
const scene = state.heavenReadingMode === "fortune" ? "fortune" : "hexagram";
heavenReadingAnimation.start(scene, heavenReadingAnimationData());
}
function stopHeavenReadingAnimation() {
heavenReadingAnimation?.stop();
}
function finishHeavenReadingAnimation() {
if (!elements.heavenReadingDialog.open || !heavenReadingAnimation?.running) {
stopHeavenReadingAnimation();
return Promise.resolve();
}
return heavenReadingAnimation.complete();
}
function openHeavenReading(mode, options = {}) {
state.heavenReadingMode = mode;
state.heavenReadingTab = "current";
@@ -3492,7 +3532,10 @@ function openHeavenReading(mode, options = {}) {
: false;
renderHeavenReadingDialog();
if (!elements.heavenReadingDialog.open) elements.heavenReadingDialog.showModal();
requestAnimationFrame(() => document.querySelector("#closeHeavenReadingDialog").focus());
requestAnimationFrame(() => {
syncHeavenReadingAnimation();
document.querySelector("#closeHeavenReadingDialog").focus();
});
}
async function openHeavenHistory(mode) {
@@ -3537,8 +3580,12 @@ function renderHeavenReadingDialog() {
});
document.querySelector("#heavenReadingCurrent").hidden = state.heavenReadingTab !== "current";
document.querySelector("#heavenReadingHistory").hidden = state.heavenReadingTab !== "history";
if (state.heavenReadingTab === "current") renderHeavenReadingCurrent();
else renderHeavenReadingHistory();
if (state.heavenReadingTab === "current") {
renderHeavenReadingCurrent();
} else {
stopHeavenReadingAnimation();
renderHeavenReadingHistory();
}
refreshIcons();
}
@@ -3550,6 +3597,7 @@ function renderHeavenReadingCurrent() {
const error = document.querySelector("#heavenReadingError");
loading.hidden = !state.heavenReadingLoading;
setText("heavenReadingLoadingTitle", heavenReadingMeta().loading);
syncHeavenReadingAnimation();
error.hidden = !state.heavenReadingError;
error.textContent = state.heavenReadingError;
result.hidden = state.heavenReadingLoading || !reading;
@@ -3644,6 +3692,7 @@ async function interpretHeaven(mode) {
created_at: new Date().toISOString(),
};
state.heavenReadingHistory[mode] = [];
await finishHeavenReadingAnimation();
state.heavenReadingLoading = false;
renderHeavenReadingDialog();
if (result.notice) showHeavenNotice(result.notice);
@@ -3653,6 +3702,7 @@ async function interpretHeaven(mode) {
renderHeavenInterpretation(mode, state.heavenInterpretations[mode]);
}
} catch (error) {
stopHeavenReadingAnimation();
state.heavenReadingLoading = false;
state.heavenReadingError = error.message || "问天解读失败";
renderHeavenReadingDialog();