natus wheel: planet/sign/house tooltip layout overhaul — TDD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,12 @@ const NatusWheel = (() => {
|
||||
'Cooperation', 'Regeneration', 'Enterprise', 'Career', 'Reward', 'Reprisal',
|
||||
];
|
||||
|
||||
// Cardinal / Fixed / Mutable — parallel index to SIGNS
|
||||
const SIGN_MODALITIES = [
|
||||
'Cardinal', 'Fixed', 'Mutable', 'Cardinal', 'Fixed', 'Mutable',
|
||||
'Cardinal', 'Fixed', 'Mutable', 'Cardinal', 'Fixed', 'Mutable',
|
||||
];
|
||||
|
||||
// ── State ─────────────────────────────────────────────────────────────────
|
||||
|
||||
let _svg = null;
|
||||
@@ -186,6 +192,21 @@ const NatusWheel = (() => {
|
||||
return ((ecliptic % 360) + 360) % 360 % 30;
|
||||
}
|
||||
|
||||
/** Return 1-based house number for an ecliptic degree given 12 cusps. */
|
||||
function _planetHouse(degree, cusps) {
|
||||
degree = ((degree % 360) + 360) % 360;
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const start = ((cusps[i] % 360) + 360) % 360;
|
||||
const end = ((cusps[(i + 1) % 12] % 360) + 360) % 360;
|
||||
if (start < end) {
|
||||
if (start <= degree && degree < end) return i + 1;
|
||||
} else {
|
||||
if (degree >= start || degree < end) return i + 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Inline SVG for a zodiac sign icon (preloaded path). */
|
||||
function _signIconSvg(signName) {
|
||||
const d = _signPaths[signName];
|
||||
@@ -400,8 +421,14 @@ const NatusWheel = (() => {
|
||||
|
||||
if (_ttBody) {
|
||||
_ttBody.innerHTML =
|
||||
`<div class="tt-title tt-title--${el}">${item.name} (${sym})</div>` +
|
||||
`<div class="tt-description">@${inDeg}° ${pdata.sign} (${icon})${rx}</div>` +
|
||||
`<div class="tt-planet-header">` +
|
||||
`<span class="tt-title tt-title--${el}">${item.name}</span>` +
|
||||
`<span class="tt-planet-sym tt-title--${el}">${sym}</span>` +
|
||||
`</div>` +
|
||||
`<div class="tt-planet-loc">` +
|
||||
`<span>@${inDeg}° ${pdata.sign}${rx}</span>` +
|
||||
`<span class="tt-planet-sign-icon">${icon}</span>` +
|
||||
`</div>` +
|
||||
aspectHtml;
|
||||
}
|
||||
|
||||
@@ -524,14 +551,41 @@ const NatusWheel = (() => {
|
||||
function _activateSign(idx) {
|
||||
_activeRing = 'signs';
|
||||
_activeIdx = idx;
|
||||
const sign = _signItems[idx];
|
||||
const sign = _signItems[idx];
|
||||
const elKey = sign.element.toLowerCase();
|
||||
const modality = SIGN_MODALITIES[idx];
|
||||
const vecImg = _elementVectorImg(sign.element);
|
||||
const iconSvg = _signIconSvg(sign.name) ||
|
||||
`<span class="tt-sign-sym-fallback">${sign.symbol}</span>`;
|
||||
|
||||
let planetsHtml = '';
|
||||
if (_currentData) {
|
||||
const cusps = (_currentData.houses || {}).cusps || [];
|
||||
const inSign = Object.entries(_currentData.planets || {})
|
||||
.filter(([, p]) => p.sign === sign.name)
|
||||
.sort((a, b) => a[1].degree - b[1].degree);
|
||||
inSign.forEach(([pname, pdata]) => {
|
||||
const psym = PLANET_SYMBOLS[pname] || pname[0];
|
||||
const inDeg = _inSignDeg(pdata.degree).toFixed(1);
|
||||
const house = cusps.length ? _planetHouse(pdata.degree, cusps) : null;
|
||||
const domain = house ? HOUSE_LABELS[house] : '';
|
||||
planetsHtml +=
|
||||
`<div class="tt-asp-row">${psym} @${inDeg}°` +
|
||||
(domain ? `, House of ${domain}` : '') + `</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
if (_ttBody) {
|
||||
_ttBody.innerHTML =
|
||||
`<div class="tt-sign-header">` +
|
||||
`<span class="tt-sign-symbol">${sign.symbol}</span>` +
|
||||
`<span class="tt-title">${sign.name}</span>` +
|
||||
`<span class="tt-sign-element"> · ${sign.element}</span>` +
|
||||
`</div>`;
|
||||
`<span class="tt-title tt-title--el-${elKey}">${sign.name}</span>` +
|
||||
`<span class="tt-sign-icon-wrap">${iconSvg}</span>` +
|
||||
`</div>` +
|
||||
`<div class="tt-sign-meta">` +
|
||||
`<span>${modality} ${sign.element}</span>` +
|
||||
vecImg +
|
||||
`</div>` +
|
||||
(planetsHtml ? `<div class="tt-sign-planets">${planetsHtml}</div>` : '');
|
||||
}
|
||||
_positionTooltipAtItem('signs', idx);
|
||||
if (_tooltipEl) {
|
||||
@@ -544,12 +598,28 @@ const NatusWheel = (() => {
|
||||
_activeRing = 'houses';
|
||||
_activeIdx = idx;
|
||||
const house = _houseItems[idx];
|
||||
const cusps = (_currentData && (_currentData.houses || {}).cusps) || [];
|
||||
|
||||
let planetsHtml = '';
|
||||
if (cusps.length && _currentData) {
|
||||
const inHouse = Object.entries(_currentData.planets || {})
|
||||
.filter(([, p]) => _planetHouse(p.degree, cusps) === house.num)
|
||||
.sort((a, b) => a[1].degree - b[1].degree);
|
||||
inHouse.forEach(([pname, pdata]) => {
|
||||
const psym = PLANET_SYMBOLS[pname] || pname[0];
|
||||
const inDeg = _inSignDeg(pdata.degree).toFixed(1);
|
||||
const sicon = _signIconSvg(pdata.sign) || (SIGNS.find(s => s.name === pdata.sign) || {}).symbol || '';
|
||||
planetsHtml += `<div class="tt-asp-row">${psym} @${inDeg}° ${sicon}</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
if (_ttBody) {
|
||||
_ttBody.innerHTML =
|
||||
`<div class="tt-house-header">` +
|
||||
`<span class="tt-title">${house.num}</span>` +
|
||||
`<span class="tt-house-label"> · ${house.label}</span>` +
|
||||
`</div>`;
|
||||
`<span class="tt-title">House of ${house.label}</span>` +
|
||||
`<span class="tt-house-num">${house.num}</span>` +
|
||||
`</div>` +
|
||||
(planetsHtml ? `<div class="tt-house-planets">${planetsHtml}</div>` : '');
|
||||
}
|
||||
_positionTooltipAtItem('houses', idx);
|
||||
if (_tooltipEl) {
|
||||
|
||||
@@ -505,10 +505,83 @@ body[class*="-light"] {
|
||||
padding: 0.75rem 0.75rem 0.75rem 1.5rem;
|
||||
min-width: 14rem;
|
||||
|
||||
.tt-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0.3rem; }
|
||||
.tt-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0; }
|
||||
.tt-description { font-size: 0.75rem; }
|
||||
.tt-sign-icon { fill: currentColor; vertical-align: middle; margin-bottom: 0.1em; }
|
||||
|
||||
// Planet tooltip — flex row: name | symbol; location row: @deg° Sign | sign icon
|
||||
.tt-planet-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.tt-planet-sym {
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.tt-planet-loc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.tt-planet-sign-icon { font-size: 1.2rem; line-height: 1; }
|
||||
|
||||
// Sign tooltip — name in element color | SVG icon; modality | vector; planets
|
||||
.tt-sign-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.tt-sign-icon-wrap {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
.tt-sign-icon { fill: currentColor; }
|
||||
}
|
||||
.tt-sign-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.85;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.tt-sign-planets {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
margin-top: 0.1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
// House tooltip — "House of X" | number; planets in house
|
||||
.tt-house-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.tt-house-num {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
opacity: 0.55;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.tt-house-planets {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
// DON|DOFF aspect line toggle — stacked at top-left outside the tooltip box,
|
||||
// matching the PRV/NXT pattern at the bottom corners.
|
||||
.nw-asp-don,
|
||||
|
||||
Reference in New Issue
Block a user