Biwheel swap: flip inner/outer chart in synastry view

Swap button re-frames the biwheel by the other chart (houses, ASC
rotation follow the outer chart); legend updates, resets per comparison,
and warns when the framing chart has an unknown birth time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-08-31 21:35:38 +10:00
parent 438b4c1b47
commit 5c03a5158b
3 changed files with 26 additions and 4 deletions

View File

@ -186,6 +186,7 @@ function filterChart(d) {
);
})();
let lastSyn = null;
let synSwapped = false;
/* ---------------- tabs ---------------- */
document.querySelectorAll("#tabs button").forEach((b) =>
@ -502,6 +503,7 @@ $("#syn-go").addEventListener("click", async () => {
});
const d = await res.json();
if (d.error) throw new Error(d.error);
synSwapped = false;
renderSynastry(d);
} catch (ex) {
err.textContent = ex.message;
@ -534,9 +536,18 @@ function renderSynastry(d0, scroll = true) {
<div class="gauge"><div class="num" style="color:var(--green)">${sc.harmony}</div><div class="lbl">harmony</div></div>
<div class="gauge"><div class="num" style="color:var(--red)">${sc.tension}</div><div class="lbl">tension</div></div>
<div class="gauge"><div class="num" style="color:var(--ink)">${sc.contacts}</div><div class="lbl">contacts</div></div>
<div id="syn-blendbar"><div style="width:${sc.blend}%"></div></div>
<p class="hint" style="flex-basis:100%">Biwheel: <span style="color:#e8e4f0">${esc(nameA)} outer</span> · <span style="color:var(--gold)">${esc(nameB)} inner</span>, in ${esc(nameA)}'s houses.</p>`;
$("#syn-wheel").innerHTML = wheelSVG(d.chart_a, d.chart_b);
<div id="syn-blendbar"><div style="width:${sc.blend}%"></div></div>`;
const base = synSwapped ? d.chart_b : d.chart_a;
const over = synSwapped ? d.chart_a : d.chart_b;
const baseName = synSwapped ? nameB : nameA;
const overName = synSwapped ? nameA : nameB;
if (base.time_unknown && !over.time_unknown) {
$("#syn-legend").innerHTML = `<span class="hint">${esc(baseName)}'s birth time is unknown — houses/rotation are its noon solar chart. Swap to frame by ${esc(overName)}.</span>`;
} else {
$("#syn-legend").innerHTML =
`Biwheel: <span style="color:#e8e4f0">${esc(baseName)} outer</span> · <span style="color:var(--gold)">${esc(overName)} inner</span>, in ${esc(baseName)}'s houses.`;
}
$("#syn-wheel").innerHTML = wheelSVG(base, over);
// inter-aspect grid: rows = A points, cols = B points
const cls = (a) => ({ Conjunction: "asp-gold", Opposition: "asp-red", Square: "asp-red", Trine: "asp-blue", Sextile: "asp-green" }[a.aspect] || "asp-dim");
@ -568,6 +579,10 @@ function renderSynastry(d0, scroll = true) {
if (scroll) $("#syn-results").scrollIntoView({ behavior: "smooth" });
}
$("#syn-print").addEventListener("click", () => window.print());
$("#syn-swap").addEventListener("click", () => {
synSwapped = !synSwapped;
if (lastSyn) renderSynastry(lastSyn, false);
});
/* ---------------- aspect reference ---------------- */
(async function loadReference() {

View File

@ -127,6 +127,10 @@
</div>
<div id="syn-results" hidden>
<div id="syn-scores"></div>
<div id="syn-wheelbar">
<span id="syn-legend"></span>
<button type="button" id="syn-swap" title="flip which chart is the outer wheel (houses follow the outer chart)">⇄ Swap inner/outer</button>
</div>
<div id="syn-wheel"></div>
<h3>Inter-Aspect Grid <span class="hint">(rows = first chart, columns = partner)</span></h3>
<div class="scrollx"><table id="syn-grid"></table></div>

View File

@ -140,6 +140,9 @@ td.dign { color: var(--gold); font-size: 12px; }
.gauge .lbl { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: 1px; }
#syn-blendbar { flex: 1; min-width: 220px; height: 14px; border-radius: 7px; background: var(--red); overflow: hidden; }
#syn-blendbar div { height: 100%; background: linear-gradient(90deg, #5cc58a, #5fa8e0); }
#syn-wheelbar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; font-size: 13px; color: var(--dim); }
#syn-swap { font-size: 13px; padding: 6px 12px; background: #1a1a2e; }
#syn-swap:hover { background: #262640; }
#syn-wheel svg { width: 100%; max-width: 720px; height: auto; display: block; margin: 0 auto; }
#syn-grid th { color: var(--gold); }
#syn-grid td, #syn-grid th { text-align: center; padding: 4px 6px; min-width: 30px; }
@ -152,7 +155,7 @@ td.dign { color: var(--gold); font-size: 12px; }
@media print {
body { background: #fff; color: #000; font-size: 12px; }
header, #form-card, #tabs, footer, #print-btn, #toolbar, #layers, #syn-picker, #syn-print { display: none !important; }
header, #form-card, #tabs, footer, #print-btn, #toolbar, #layers, #syn-picker, #syn-print, #syn-swap { display: none !important; }
#results { border: none; background: none; }
.tab { display: block !important; }
#report .item b, #report h4, h3 { color: #000; }