sky wheel: element contributor display; sign + house tooltips — TDD
sky_save now re-fetches from PySwiss server-side on save so stored chart_data always carries enriched element format (contributors/stellia/ parades). New sky/data endpoint serves fresh PySwiss data to the My Sky applet on load, replacing the stale inline json_script approach. natus-wheel.js: sign ring slices (data-sign-name) and house ring slices (data-house) now have click handlers with _activateSign/_activateHouse; em-dash fallback added for classic elements with empty contributor lists. Action URLs sky/preview, sky/save, sky/data lose trailing slashes. Jasmine: T12 sign tooltip, T13 house tooltip, T14 enriched element contributor display (symbols, Stellium/Parade formations, em-dash fallback). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -551,3 +551,271 @@ xdescribe("NatusWheel — half-wheel tooltip positioning", () => {
|
||||
expect(parseFloat(tooltipEl.style.left)).toBe(270);
|
||||
});
|
||||
});
|
||||
|
||||
// ── T14 — element tooltip shows contributor planets (enriched data) ───────────
|
||||
//
|
||||
// When element data arrives in enriched format {count, contributors/stellia/parades},
|
||||
// clicking a classic-element slice lists contributor planet names in the tooltip.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("NatusWheel — element tooltip contributor display", () => {
|
||||
|
||||
const ENRICHED_CHART = {
|
||||
planets: {
|
||||
Sun: { sign: "Gemini", degree: 66.7, retrograde: false },
|
||||
Venus: { sign: "Gemini", degree: 63.3, retrograde: false },
|
||||
Mars: { sign: "Leo", degree: 132.0, retrograde: false },
|
||||
Saturn: { sign: "Virgo", degree: 153.0, retrograde: false },
|
||||
},
|
||||
houses: {
|
||||
cusps: [180, 210, 240, 270, 300, 330, 0, 30, 60, 90, 120, 150],
|
||||
asc: 180.0, mc: 90.0,
|
||||
},
|
||||
elements: {
|
||||
Fire: { count: 2, contributors: [
|
||||
{ planet: "Sun", sign: "Gemini" },
|
||||
{ planet: "Mars", sign: "Leo" },
|
||||
]},
|
||||
Stone: { count: 1, contributors: [
|
||||
{ planet: "Saturn", sign: "Virgo" },
|
||||
]},
|
||||
Air: { count: 0, contributors: [] },
|
||||
Water: { count: 0, contributors: [] },
|
||||
Time: { count: 1, stellia: [
|
||||
{ sign: "Gemini", planets: [
|
||||
{ planet: "Sun", sign: "Gemini" },
|
||||
{ planet: "Venus", sign: "Gemini" },
|
||||
]},
|
||||
]},
|
||||
Space: { count: 1, parades: [
|
||||
{ signs: ["Gemini", "Leo", "Virgo"],
|
||||
planets: [
|
||||
{ planet: "Sun", sign: "Gemini" },
|
||||
{ planet: "Mars", sign: "Leo" },
|
||||
{ planet: "Saturn", sign: "Virgo" },
|
||||
]},
|
||||
]},
|
||||
},
|
||||
aspects: [],
|
||||
distinctions: { "1":0,"2":0,"3":2,"4":0,"5":0,"6":0,"7":0,"8":0,"9":1,"10":0,"11":0,"12":0 },
|
||||
house_system: "O",
|
||||
};
|
||||
|
||||
let svgEl, tooltipEl;
|
||||
|
||||
beforeEach(() => {
|
||||
svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svgEl.setAttribute("id", "id_natus_svg");
|
||||
svgEl.setAttribute("width", "400");
|
||||
svgEl.setAttribute("height", "400");
|
||||
svgEl.style.width = "400px";
|
||||
svgEl.style.height = "400px";
|
||||
document.body.appendChild(svgEl);
|
||||
|
||||
tooltipEl = document.createElement("div");
|
||||
tooltipEl.id = "id_natus_tooltip";
|
||||
tooltipEl.className = "tt";
|
||||
tooltipEl.style.display = "none";
|
||||
document.body.appendChild(tooltipEl);
|
||||
|
||||
NatusWheel.draw(svgEl, ENRICHED_CHART);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
NatusWheel.clear();
|
||||
svgEl.remove();
|
||||
tooltipEl.remove();
|
||||
});
|
||||
|
||||
// T14a — Fire slice lists contributor planet symbols ☉ (Sun) and ♂ (Mars)
|
||||
it("T14a: clicking Fire element slice shows contributor planet symbols", () => {
|
||||
const fireSlice = svgEl.querySelector("[data-element='Fire']");
|
||||
expect(fireSlice).not.toBeNull();
|
||||
fireSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
|
||||
expect(tooltipEl.style.display).not.toBe("none");
|
||||
const body = tooltipEl.querySelector(".nw-tt-body").innerHTML;
|
||||
expect(body).toContain("☉"); // Sun
|
||||
expect(body).toContain("♂"); // Mars
|
||||
});
|
||||
|
||||
// T14b — Space slice shows parade formation with planet symbols
|
||||
it("T14b: clicking Space element slice shows parade formation block", () => {
|
||||
const spaceSlice = svgEl.querySelector("[data-element='Space']");
|
||||
spaceSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
|
||||
const body = tooltipEl.querySelector(".nw-tt-body").innerHTML;
|
||||
expect(body).toContain("Parade");
|
||||
// Planet symbols for Sun ☉, Mars ♂, Saturn ♄ appear in the parade
|
||||
expect(body).toContain("☉");
|
||||
});
|
||||
|
||||
// T14c — Time slice shows stellium formation with planet symbols
|
||||
it("T14c: clicking Time element slice shows stellium formation block", () => {
|
||||
const timeSlice = svgEl.querySelector("[data-element='Time']");
|
||||
timeSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
|
||||
const body = tooltipEl.querySelector(".nw-tt-body").innerHTML;
|
||||
expect(body).toContain("Stellium");
|
||||
// Sun ☉ and Venus ♀ are in the Gemini stellium
|
||||
expect(body).toContain("☉");
|
||||
expect(body).toContain("♀");
|
||||
});
|
||||
|
||||
// T14d — Air slice (count 0) shows em dash fallback, not an empty list
|
||||
it("T14d: empty element slice shows em dash fallback", () => {
|
||||
const airSlice = svgEl.querySelector("[data-element='Air']");
|
||||
airSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
|
||||
const body = tooltipEl.querySelector(".nw-tt-body").innerHTML;
|
||||
expect(body).toContain("—");
|
||||
});
|
||||
});
|
||||
|
||||
// ── T12 — sign ring click tooltips ────────────────────────────────────────────
|
||||
//
|
||||
// Clicking a sign slice shows:
|
||||
// ♉ Taurus · Stone
|
||||
// Clicking the same sign again closes the tooltip.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("NatusWheel — sign ring click tooltips", () => {
|
||||
|
||||
const SIGN_CHART = {
|
||||
planets: {
|
||||
Sun: { sign: "Taurus", degree: 40.0, retrograde: false },
|
||||
},
|
||||
houses: {
|
||||
cusps: [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330],
|
||||
asc: 0,
|
||||
mc: 270,
|
||||
},
|
||||
elements: { Fire: 0, Stone: 1, Air: 0, Water: 0, Time: 0, Space: 0 },
|
||||
aspects: [],
|
||||
distinctions: { "1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0 },
|
||||
house_system: "O",
|
||||
};
|
||||
|
||||
let svgEl, tooltipEl;
|
||||
|
||||
beforeEach(() => {
|
||||
svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svgEl.setAttribute("id", "id_natus_svg");
|
||||
svgEl.setAttribute("width", "400");
|
||||
svgEl.setAttribute("height", "400");
|
||||
svgEl.style.width = "400px";
|
||||
svgEl.style.height = "400px";
|
||||
document.body.appendChild(svgEl);
|
||||
|
||||
tooltipEl = document.createElement("div");
|
||||
tooltipEl.id = "id_natus_tooltip";
|
||||
tooltipEl.className = "tt";
|
||||
tooltipEl.style.display = "none";
|
||||
document.body.appendChild(tooltipEl);
|
||||
|
||||
NatusWheel.draw(svgEl, SIGN_CHART);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
NatusWheel.clear();
|
||||
svgEl.remove();
|
||||
tooltipEl.remove();
|
||||
});
|
||||
|
||||
// T12a — clicking a sign shows symbol + name + element
|
||||
it("T12a: clicking a sign slice shows sign symbol, name, and element", () => {
|
||||
const taurusSlice = svgEl.querySelector("[data-sign-name='Taurus']");
|
||||
expect(taurusSlice).not.toBeNull();
|
||||
taurusSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
|
||||
expect(tooltipEl.style.display).not.toBe("none");
|
||||
const bodyText = tooltipEl.querySelector(".nw-tt-body").innerHTML;
|
||||
expect(bodyText).toContain("Taurus");
|
||||
expect(bodyText).toContain("Stone");
|
||||
expect(bodyText).toContain("♉");
|
||||
});
|
||||
|
||||
// T12b — clicking same sign again closes the tooltip
|
||||
it("T12b: clicking the same sign again hides the tooltip", () => {
|
||||
const taurusSlice = svgEl.querySelector("[data-sign-name='Taurus']");
|
||||
taurusSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
expect(tooltipEl.style.display).not.toBe("none");
|
||||
|
||||
taurusSlice.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
expect(tooltipEl.style.display).toBe("none");
|
||||
});
|
||||
});
|
||||
|
||||
// ── T13 — house ring click tooltips ───────────────────────────────────────────
|
||||
//
|
||||
// Clicking a house slice shows:
|
||||
// 3 · Education
|
||||
// Clicking the same house again closes the tooltip.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("NatusWheel — house ring click tooltips", () => {
|
||||
|
||||
const HOUSE_CHART = {
|
||||
planets: {
|
||||
Sun: { sign: "Gemini", degree: 66.7, retrograde: false },
|
||||
},
|
||||
houses: {
|
||||
cusps: [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330],
|
||||
asc: 0,
|
||||
mc: 270,
|
||||
},
|
||||
elements: { Fire: 1, Stone: 0, Air: 0, Water: 0, Time: 0, Space: 0 },
|
||||
aspects: [],
|
||||
distinctions: { "1":0,"2":0,"3":1,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0 },
|
||||
house_system: "O",
|
||||
};
|
||||
|
||||
let svgEl, tooltipEl;
|
||||
|
||||
beforeEach(() => {
|
||||
svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svgEl.setAttribute("id", "id_natus_svg");
|
||||
svgEl.setAttribute("width", "400");
|
||||
svgEl.setAttribute("height", "400");
|
||||
svgEl.style.width = "400px";
|
||||
svgEl.style.height = "400px";
|
||||
document.body.appendChild(svgEl);
|
||||
|
||||
tooltipEl = document.createElement("div");
|
||||
tooltipEl.id = "id_natus_tooltip";
|
||||
tooltipEl.className = "tt";
|
||||
tooltipEl.style.display = "none";
|
||||
document.body.appendChild(tooltipEl);
|
||||
|
||||
NatusWheel.draw(svgEl, HOUSE_CHART);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
NatusWheel.clear();
|
||||
svgEl.remove();
|
||||
tooltipEl.remove();
|
||||
});
|
||||
|
||||
// T13a — clicking a house slice shows house number + label
|
||||
it("T13a: clicking a house slice shows house number and house label", () => {
|
||||
// House 3 is at index 2 (zero-based), cusps[2]=60° span
|
||||
const house3 = svgEl.querySelector("[data-house='3']");
|
||||
expect(house3).not.toBeNull();
|
||||
house3.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
|
||||
expect(tooltipEl.style.display).not.toBe("none");
|
||||
const bodyText = tooltipEl.querySelector(".nw-tt-body").innerHTML;
|
||||
expect(bodyText).toContain("3");
|
||||
expect(bodyText).toContain("Education");
|
||||
});
|
||||
|
||||
// T13b — clicking same house again closes the tooltip
|
||||
it("T13b: clicking the same house again hides the tooltip", () => {
|
||||
const house3 = svgEl.querySelector("[data-house='3']");
|
||||
house3.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
expect(tooltipEl.style.display).not.toBe("none");
|
||||
|
||||
house3.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
expect(tooltipEl.style.display).toBe("none");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user