// astrology.jsx - natal chart wheel renderer for Azoth AI const ASTRO_ZODIAC = [ { name: "Овен" }, { name: "Телець" }, { name: "Близнюки" }, { name: "Рак" }, { name: "Лев" }, { name: "Діва" }, { name: "Терези" }, { name: "Скорпіон" }, { name: "Стрілець" }, { name: "Козоріг" }, { name: "Водолій" }, { name: "Риби" }, ]; const ZODIAC_SVG_PATHS = [ ["M0 10 C0 2 -2 -3 -7 -6 C-10 -8 -12 -5 -11 -1", "M0 10 C0 2 2 -3 7 -6 C10 -8 12 -5 11 -1"], ["M-9 -6 C-5 -2 -2 -1 0 -1 C2 -1 5 -2 9 -6", "M-8 4 A8 8 0 1 0 8 4 A8 8 0 1 0 -8 4"], ["M-8 -9 L-8 9", "M8 -9 L8 9", "M-10 -8 C-4 -5 4 -5 10 -8", "M-10 8 C-4 5 4 5 10 8"], ["M9 -5 C5 -10 -4 -9 -6 -3 C-8 3 -1 5 3 2", "M-9 5 C-5 10 4 9 6 3 C8 -3 1 -5 -3 -2", "M-5 -2 A3 3 0 1 0 -5 -8 A3 3 0 1 0 -5 -2", "M5 8 A3 3 0 1 0 5 2 A3 3 0 1 0 5 8"], ["M-10 4 C-14 0 -11 -9 -4 -9 C2 -9 4 -4 2 1", "M2 1 C-1 7 5 13 12 7", "M-8 8 C-3 8 1 5 2 1"], ["M-13 9 L-13 -8", "M-7 9 L-7 -7 C-5 -10 -1 -10 1 -7 L1 9", "M1 -7 C3 -10 8 -10 10 -6 L10 6", "M10 6 C10 12 2 12 2 6 C2 1 10 1 14 -3", "M8 7 L14 -2"], ["M-14 9 L14 9", "M-12 2 L-5 2", "M5 2 L12 2", "M-5 2 C-5 -6 5 -6 5 2"], ["M-11 8 L-11 -7", "M-5 8 L-5 -6 C-3 -9 1 -9 3 -6 L3 7", "M3 7 L8 2", "M8 2 L10 6", "M8 2 L5 1"], ["M-7 7 L9 -9", "M2 -9 L9 -9 L9 -2", "M-1 -4 L6 3"], ["M-13 8 L-13 -8 C-9 -3 -6 0 -4 5", "M-4 5 L-4 -8 C0 -4 2 2 2 7", "M2 7 C2 13 12 12 12 5 C12 -2 4 -2 4 5", "M5 8 C8 7 11 4 12 1"], ["M-11 -2 C-6 -6 -2 2 3 -2 C7 -5 9 -3 11 -2", "M-11 6 C-6 2 -2 10 3 6 C7 3 9 5 11 6"], ["M-11 -11 C-4 -4 -4 4 -11 11", "M11 -11 C4 -4 4 4 11 11", "M-14 0 L14 0"], ]; function astroAngle(lon, asc) { return ((Number(lon || 0) - Number(asc || 0)) * Math.PI) / 180 + Math.PI; } function astroPoint(cx, cy, r, lon, asc) { const a = astroAngle(lon, asc); return { x: cx + Math.cos(a) * r, y: cy + Math.sin(a) * r }; } function aspectClass(aspect) { if (aspect === "з'єднання") return "conjunction"; if (aspect === "трин") return "trine"; if (aspect === "секстиль") return "sextile"; if (aspect === "квадрат") return "square"; if (aspect === "опозиція") return "opposition"; return "other"; } function ZodiacGlyph({ index, x, y, size = 62 }) { const paths = ZODIAC_SVG_PATHS[index] || []; const radius = size / 2; const glyphScale = (size * 0.54) / 34; return ( {paths.map((d, i) => )} ); } function NatalChartView({ chart }) { if (!chart || chart.type !== "natal_chart" || !chart.asc || !chart.planets) return null; const size = 660; const c = size / 2; const asc = chart.asc.lon; const zodiacR = 284; const houseR = 236; const planetR = 190; const planetPoints = chart.planets.map((planet, index) => { const radial = planetR - (index % 3) * 16; return { ...planet, ...astroPoint(c, c, radial, planet.lon, asc), radial }; }); const chartKey = `${chart.date || "date"}-${chart.time || "time"}`.replace(/[^a-zA-Z0-9_-]/g, ""); return (
Natal Chart · {chart.zodiac} · {chart.houses}
Натальна карта
{chart.date} · {chart.time} {chart.place?.name || "місце"} · {chart.offset}
{ASTRO_ZODIAC.map((sign, i) => { const start = astroPoint(c, c, zodiacR, i * 30, asc); const label = astroPoint(c, c, zodiacR + 9, i * 30 + 15, asc); return ( ); })} {(chart.cusps || []).map(cusp => { const p = astroPoint(c, c, houseR, cusp.lon, asc); const label = astroPoint(c, c, 126, cusp.lon + 9, asc); return ( {cusp.house} ); })} {(chart.aspects || []).slice(0, 14).map((aspect, i) => { const left = planetPoints.find(p => p.name === aspect.left); const right = planetPoints.find(p => p.name === aspect.right); if (!left || !right) return null; return ; })} {planetPoints.map((planet, i) => ( {planet.glyph} ))} ASC {chart.asc.label} MC {chart.mc.label} AZOTH tropical · Placidus
ASC{chart.asc.label}
MC{chart.mc.label}
{chart.planets.map(planet => (
{planet.glyph}{planet.name} {planet.position}{planet.retrograde ? " R" : ""} {planet.house} дім
))}
{(chart.aspects || []).slice(0, 6).map((aspect, i) => (
{aspect.left} {aspect.aspect} {aspect.right}{aspect.orb}°
))}
); } Object.assign(window, { NatalChartView });