nocturna-wheel
Version:
A JavaScript library for rendering astrological natal charts
1 lines • 52.9 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).NocturnaWheel={})}(this,(function(e){"use strict";class t{static#e=new Map;static register(e,t){this.#e.set(e,t)}static get(e){return this.#e.get(e)}static has(e){return this.#e.has(e)}static clear(){this.#e.clear()}static getSvgUtils(){if(!this.has("svgUtils")){const e={svgNS:"http://www.w3.org/2000/svg",createSVGElement(e,t={}){const s=document.createElementNS(this.svgNS,e);for(const[e,n]of Object.entries(t))s.setAttribute(e,n);return s},addTooltip(e,t){const s=document.createElementNS(this.svgNS,"title");return s.textContent=t,e.appendChild(s),e},pointOnCircle(e,t,s,n){const i=(n-90)*(Math.PI/180);return{x:e+s*Math.cos(i),y:t+s*Math.sin(i)}}};this.register("svgUtils",e)}return this.get("svgUtils")}static getIconProvider(e="./assets/svg/zodiac/"){if(!this.has("iconProvider")){const t={basePath:e,getPlanetIconPath(e){return`${this.basePath}zodiac-planet-${e.toLowerCase()}.svg`},getZodiacIconPath(e){return`${this.basePath}zodiac-sign-${e.toLowerCase()}.svg`},getAspectIconPath(e){return`${this.basePath}zodiac-aspect-${e.toLowerCase()}.svg`},createTextFallback(e,t,s){const{x:n,y:i,size:r="16px",color:o="#000000",className:a="icon-fallback"}=t,c=e.createSVGElement("text",{x:n,y:i,"text-anchor":"middle","dominant-baseline":"middle","font-size":r,class:a,fill:o});return c.textContent=s,c}};this.register("iconProvider",t)}return this.get("iconProvider")}static initializeServices(e={}){this.getSvgUtils(),this.getIconProvider(e.assetBasePath||"./assets/svg/zodiac/"),console.log("ServiceRegistry: Core services initialized")}}class s{constructor(e={}){this.astronomicalData={ascendant:0,mc:90,latitude:51.5,houseSystem:"Placidus",planets:{sun:0,moon:0,mercury:0,venus:0,mars:0,jupiter:0,saturn:0,uranus:0,neptune:0,pluto:0}},this.aspectSettings={enabled:!0,orb:6,types:{conjunction:{angle:0,orb:8,color:"#ff0000",enabled:!0},opposition:{angle:180,orb:8,color:"#0000ff",enabled:!0},trine:{angle:120,orb:6,color:"#00ff00",enabled:!0},square:{angle:90,orb:6,color:"#ff00ff",enabled:!0},sextile:{angle:60,orb:4,color:"#00ffff",enabled:!0}}},this.planetSettings={enabled:!0,primaryEnabled:!0,secondaryEnabled:!0,dotSize:3,iconSize:24,orbs:{sun:8,moon:8,mercury:6,venus:6,mars:6,jupiter:6,saturn:6,uranus:4,neptune:4,pluto:4},colors:{sun:"#ff9900",moon:"#aaaaaa",mercury:"#3399cc",venus:"#cc66cc",mars:"#cc3333",jupiter:"#9966cc",saturn:"#336633",uranus:"#33cccc",neptune:"#3366ff",pluto:"#663366"},visible:{sun:!0,moon:!0,mercury:!0,venus:!0,mars:!0,jupiter:!0,saturn:!0,uranus:!0,neptune:!0,pluto:!0}},this.houseSettings={enabled:!0,lineColor:"#666666",textColor:"#333333",fontSize:10,rotationAngle:0},this.zodiacSettings={enabled:!0,colors:{aries:"#ff6666",taurus:"#66cc66",gemini:"#ffcc66",cancer:"#6699cc",leo:"#ff9900",virgo:"#996633",libra:"#6699ff",scorpio:"#cc3366",sagittarius:"#cc66ff",capricorn:"#339966",aquarius:"#3399ff",pisces:"#9966cc"},fontSize:10},this.radius={innermost:90,zodiacInner:120,zodiacMiddle:150,zodiacOuter:180,planet:105,aspectInner:20,aspectOuter:120,houseNumberRadius:210},this.svg={width:460,height:460,viewBox:"0 0 460 460",center:{x:230,y:230}},this.assets={basePath:"./assets/",zodiacIconPath:"svg/zodiac/",planetIconPath:"svg/zodiac/"},this.theme={backgroundColor:"transparent",textColor:"#333333",lineColor:"#666666",lightLineColor:"#cccccc",fontFamily:"'Arial', sans-serif"},this.houseCusps=[],this.mergeConfig(e),this._initializeHouseCusps()}mergeConfig(e){const t=(e,s)=>{if("object"!=typeof s||null===s)return s;for(const n in s)Object.prototype.hasOwnProperty.call(s,n)&&("object"==typeof s[n]&&null!==s[n]&&"object"==typeof e[n]&&null!==e[n]?e[n]=t(e[n],s[n]):e[n]=s[n]);return e};for(const s in e)Object.prototype.hasOwnProperty.call(e,s)&&Object.prototype.hasOwnProperty.call(this,s)&&(this[s]=t(this[s],e[s]))}_initializeHouseCusps(){if("number"==typeof this.astronomicalData.ascendant&&"number"==typeof this.astronomicalData.mc)try{const e=new HouseCalculator;this.houseCusps=e.calculateHouseCusps(this.astronomicalData.ascendant,this.astronomicalData.houseSystem,{latitude:this.astronomicalData.latitude,mc:this.astronomicalData.mc})}catch(e){console.error("Failed to calculate house cusps:",e),this.houseCusps=[]}}getPlanetSettings(e){const t=e.toLowerCase();return{color:this.planetSettings.colors[t]||"#000000",size:this.planetSettings.size,visible:!1!==this.planetSettings.visible[t]}}getAspectSettings(e){const t=e.toLowerCase();return this.aspectSettings.types[t]||{angle:0,orb:this.aspectSettings.orb,color:"#999999",enabled:!0}}getZodiacSettings(e){const t=e.toLowerCase();return{color:this.zodiacSettings.colors[t]||"#666666",fontSize:this.zodiacSettings.fontSize}}updateAspectSettings(e){this.aspectSettings={...this.aspectSettings,...e}}updatePlanetSettings(e){this.planetSettings={...this.planetSettings,...e}}updateHouseSettings(e){this.houseSettings={...this.houseSettings,...e}}updateZodiacSettings(e){this.zodiacSettings={...this.zodiacSettings,...e}}setRadius(e,t){Object.prototype.hasOwnProperty.call(this.radius,e)&&(this.radius[e]=t)}togglePlanetVisibility(e,t){this.planetSettings&&this.planetSettings.visible&&(this.planetSettings.visible[e]=t)}toggleHousesVisibility(e){this.houseSettings.enabled=e}toggleAspectsVisibility(e){this.aspectSettings.enabled=e}togglePrimaryPlanetsVisibility(e){this.planetSettings.primaryEnabled=e}toggleSecondaryPlanetsVisibility(e){this.planetSettings.secondaryEnabled=e}setHouseSystem(e){return this.astronomicalData.houseSystem=e,this._initializeHouseCusps(),!0}getHouseCusps(){return this.houseCusps&&0!==this.houseCusps.length||this._initializeHouseCusps(),this.houseCusps.length>0&&"number"==typeof this.houseCusps[0]?this.houseCusps.map((e=>({lon:e}))):this.houseCusps}setAscendant(e){return!("number"!=typeof e||e<0||e>=360)&&(this.astronomicalData.ascendant=e,this._initializeHouseCusps(),!0)}setMidheaven(e){return!("number"!=typeof e||e<0||e>=360)&&(this.astronomicalData.mc=e,this._initializeHouseCusps(),!0)}setLatitude(e){return!("number"!=typeof e||e<-90||e>90)&&(this.astronomicalData.latitude=e,this._initializeHouseCusps(),!0)}setPlanetPosition(e,t){const s=e.toLowerCase();return!("number"!=typeof t||t<0||t>=360)&&(!!this.astronomicalData.planets.hasOwnProperty(s)&&(this.astronomicalData.planets[s]=t,!0))}getPlanetPosition(e){const t=e.toLowerCase();return this.astronomicalData.planets.hasOwnProperty(t)?this.astronomicalData.planets[t]:null}getHouseSystem(){return this.astronomicalData.houseSystem}getAvailableHouseSystems(){return(new HouseCalculator).getAvailableHouseSystems()}}class n{constructor(){this.svgNS="http://www.w3.org/2000/svg"}createSVGElement(e,t={}){const s=document.createElementNS(this.svgNS,e);for(const[e,n]of Object.entries(t))s.setAttribute(e,n);return s}addTooltip(e,t){const s=document.createElementNS(this.svgNS,"title");return s.textContent=t,e.appendChild(s),e}pointOnCircle(e,t,s,n){const i=(n-90)*(Math.PI/180);return{x:e+s*Math.cos(i),y:t+s*Math.sin(i)}}}class i{constructor(e={}){this.svgNS="http://www.w3.org/2000/svg",this.svg=null,this.groups={},this.svgUtils=e.svgUtils||t.getSvgUtils(),this.groupOrder=["zodiac","houseDivisions","aspects","primaryPlanets","secondaryPlanets","houses"]}initialize(e,t={}){let s;if("string"==typeof e){if(s=document.querySelector(e),!s)return console.error(`SVGManager: Container not found with selector: ${e}`),null}else{if(!(e instanceof Element||e instanceof HTMLElement))return console.error("SVGManager: Invalid container. Expected string selector or DOM element."),null;s=e}s.innerHTML="";const n={width:"100%",height:"100%",viewBox:"0 0 460 460",preserveAspectRatio:"xMidYMid meet",class:"nocturna-wheel-svg",...t};this.svg=document.createElementNS(this.svgNS,"svg");for(const[e,t]of Object.entries(n))this.svg.setAttribute(e,t);return s.appendChild(this.svg),console.log("SVGManager: SVG initialized"),this.svg}createStandardGroups(){this.svg?(this.groups={},this.svg.querySelectorAll("g").forEach((e=>e.remove())),console.log("SVGManager: Creating standard groups:",this.groupOrder),this.groupOrder.forEach((e=>{this.createGroup(e)})),this.createGroup("planets")):console.error("SVGManager: Cannot create groups, SVG not initialized.")}createGroup(e){if(!this.svg)return console.error(`SVGManager: Cannot create group '${e}', SVG not initialized.`),null;if(this.groups[e])return this.groups[e];const t=document.createElementNS(this.svgNS,"g");return t.setAttribute("id",`group-${e}`),t.setAttribute("class",`svg-group svg-group-${e}`),this.svg.appendChild(t),this.groups[e]=t,t}getGroup(e){return this.svg?("planets"===e&&(console.warn('SVGManager: Using deprecated "planets" group. Use "primaryPlanets" or "secondaryPlanets" instead.'),e="primaryPlanets"),this.groups[e]?this.groups[e]:(console.warn(`SVGManager: Group '${e}' not found. Creating it.`),this.createGroup(e))):(console.warn(`SVGManager: Cannot get group '${e}', SVG not initialized.`),null)}getAllGroups(){return this.groups}getSVG(){return this.svg}}class r{constructor(e){if(!e||!e.svgNS||!e.config)throw new Error(`${this.constructor.name}: Missing required options (svgNS, config)`);this.svgNS=e.svgNS,this.config=e.config,this.options=e,this.svgUtils=e.svgUtils||{svgNS:this.svgNS,createSVGElement:(e,t={})=>{const s=document.createElementNS(this.svgNS,e);for(const[e,n]of Object.entries(t))s.setAttribute(e,n);return s},addTooltip:(e,t)=>{const s=document.createElementNS(this.svgNS,"title");return s.textContent=t,e.appendChild(s),e},pointOnCircle:(e,t,s,n)=>{const i=(n-90)*(Math.PI/180);return{x:e+s*Math.cos(i),y:t+s*Math.sin(i)}}},this.centerX=this.config.svg.center.x,this.centerY=this.config.svg.center.y,this.innerRadius=this.config.radius.zodiacInner,this.middleRadius=this.config.radius.zodiacMiddle,this.outerRadius=this.config.radius.zodiacOuter}clearGroup(e){e&&(e.innerHTML="")}render(e){throw new Error(`${this.constructor.name}: render() not implemented.`)}}class o{static capitalizeFirstLetter(e){return e.charAt(0).toUpperCase()+e.slice(1)}static getHouseFromPosition(e,t=0){const s=(e-t+360)%360;return Math.floor(s/30)+1}static getZodiacSigns(){return["aries","taurus","gemini","cancer","leo","virgo","libra","scorpio","sagittarius","capricorn","aquarius","pisces"]}static getHouseSystems(){return{Placidus:"Most commonly used house system in Western astrology, based on time of day",Koch:"Developed by Walter Koch, a time-based system similar to Placidus",Campanus:"Medieval system dividing the prime vertical into equal parts",Regiomontanus:"Similar to Campanus, but using the celestial equator instead of prime vertical",Equal:"Divides the ecliptic into 12 equal segments of 30° each from the Ascendant","Whole Sign":"Assigns the entire rising sign to the 1st house, with subsequent signs as houses",Porphyry:"Simple system that divides each quadrant into three equal parts",Topocentric:"Modern system similar to Placidus but more accurate for extreme latitudes"}}static getPlanets(){return["sun","moon","mercury","venus","mars","jupiter","saturn","uranus","neptune","pluto"]}static houseToRoman(e){return["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII"][e-1]||""}static getPlanetFullName(e,t="en"){const s={en:{sun:"Sun",moon:"Moon",mercury:"Mercury",venus:"Venus",mars:"Mars",jupiter:"Jupiter",saturn:"Saturn",uranus:"Uranus",neptune:"Neptune",pluto:"Pluto"},ru:{sun:"Солнце",moon:"Луна",mercury:"Меркурий",venus:"Венера",mars:"Марс",jupiter:"Юпитер",saturn:"Сатурн",uranus:"Уран",neptune:"Нептун",pluto:"Плутон"}};return(s[t]||s.en)[e.toLowerCase()]||this.capitalizeFirstLetter(e)}static getZodiacSignFullName(e,t="en"){const s={en:{aries:"Aries",taurus:"Taurus",gemini:"Gemini",cancer:"Cancer",leo:"Leo",virgo:"Virgo",libra:"Libra",scorpio:"Scorpio",sagittarius:"Sagittarius",capricorn:"Capricorn",aquarius:"Aquarius",pisces:"Pisces"},ru:{aries:"Овен",taurus:"Телец",gemini:"Близнецы",cancer:"Рак",leo:"Лев",virgo:"Дева",libra:"Весы",scorpio:"Скорпион",sagittarius:"Стрелец",capricorn:"Козерог",aquarius:"Водолей",pisces:"Рыбы"}};return(s[t]||s.en)[e.toLowerCase()]||this.capitalizeFirstLetter(e)}}class a extends r{constructor(e){if(super(e),!e.assetBasePath)throw new Error("ZodiacRenderer: Missing required option assetBasePath");this.iconProvider=e.iconProvider,this.signIconRadius=(this.outerRadius+this.middleRadius)/2,this.signIconSize=30}render(e){if(!e)return console.error("ZodiacRenderer: parentGroup is null or undefined."),[];this.clearGroup(e);const t=[];return t.push(...this.renderBaseCircles(e)),t.push(...this.renderDivisionLines(e)),t.push(...this.renderZodiacSigns(e)),console.log("ZodiacRenderer: Rendering complete."),t}renderBaseCircles(e){const t=[];return[{r:this.outerRadius,class:"chart-outer-circle"},{r:this.middleRadius,class:"chart-middle-circle"},{r:this.innerRadius,class:"chart-inner-circle"}].forEach((s=>{const n=this.svgUtils.createSVGElement("circle",{cx:this.centerX,cy:this.centerY,r:s.r,class:`zodiac-element ${s.class}`});e.appendChild(n),t.push(n)})),t}renderDivisionLines(e){const t=[];for(let s=0;s<12;s++){const n=30*s,i=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.middleRadius,n),r=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.outerRadius,n);let o="";0===n?o="aries-point":90===n?o="cancer-point":180===n?o="libra-point":270===n&&(o="capricorn-point");const a=this.svgUtils.createSVGElement("line",{x1:i.x,y1:i.y,x2:r.x,y2:r.y,class:`zodiac-element zodiac-division-line ${o}`});e.appendChild(a),t.push(a)}return t}renderZodiacSigns(e){const t=[],s=o.getZodiacSigns();for(let n=0;n<12;n++){const i=s[n],r=30*n+15,a=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.signIconRadius,r);let c;c=this.iconProvider?this.iconProvider.getZodiacIconPath(i):`${this.options.assetBasePath}svg/zodiac/zodiac-sign-${i}.svg`,console.log(`Loading zodiac sign: ${c}`);const l=this.svgUtils.createSVGElement("image",{x:a.x-this.signIconSize/2,y:a.y-this.signIconSize/2,width:this.signIconSize,height:this.signIconSize,href:c,class:`zodiac-element zodiac-sign zodiac-sign-${i}`});l.addEventListener("error",(()=>{console.warn(`Zodiac sign icon not found: ${c}`),l.setAttribute("href","");const s=i.substring(0,3).toUpperCase();let n;this.iconProvider?n=this.iconProvider.createTextFallback(this.svgUtils,{x:a.x,y:a.y,size:"10px",color:"#ccc",className:`zodiac-element zodiac-sign zodiac-sign-${i}`},s):(n=this.svgUtils.createSVGElement("text",{x:a.x,y:a.y,"text-anchor":"middle","dominant-baseline":"central","font-size":"10px",fill:"#ccc",class:`zodiac-element zodiac-sign zodiac-sign-${i}`}),n.textContent=s),e.appendChild(n),t.push(n)})),this.svgUtils.addTooltip(l,o.getZodiacSignFullName(i)),e.appendChild(l),t.push(l)}return t}}class c extends r{constructor(e){super(e),this.houseData=e.houseData||[],this.extendedRadius=this.outerRadius+25,this.numberRadius=this.outerRadius+30}render(e,t=0){if(!e)return console.error("HouseRenderer: parentGroup is null or undefined."),[];this.clearGroup(e);const s=[];return s.push(...this.renderDivisions(e,t)),s.push(...this.renderNumbers(e,t)),console.log("HouseRenderer: Rendering complete."),s}renderDivisions(e,t){const s=[];let n=0;if(console.log("HouseRenderer: House data for divisions:",this.houseData),this.houseData&&this.houseData.length>=12){n=(360-this.getHouseLongitude(this.houseData[0]))%360}for(let i=0;i<12;i++){let r;r=this.houseData&&this.houseData.length>=12?this.getHouseLongitude(this.houseData[i]):30*i;const o=(r+n+t)%360;let a="";0===i?a="axis asc":3===i?a="axis ic":6===i?a="axis dsc":9===i&&(a="axis mc");const c=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.innerRadius,o),l=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.middleRadius,o),h=this.svgUtils.createSVGElement("line",{x1:c.x,y1:c.y,x2:l.x,y2:l.y,class:`house-element house-division-line ${a}`});a.includes("axis")&&(h.style.zIndex=10),e.appendChild(h),s.push(h);const d=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.outerRadius,o),u=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.extendedRadius,o),g=this.svgUtils.createSVGElement("line",{x1:d.x,y1:d.y,x2:u.x,y2:u.y,class:`house-element house-division-line outer ${a}`});a.includes("axis")&&(g.style.zIndex=10),e.appendChild(g),s.push(g)}return s}renderNumbers(e,t){const s=[];let n=0;if(console.log("HouseRenderer: House data for numbers:",this.houseData),this.houseData&&this.houseData.length>=12){n=(360-this.getHouseLongitude(this.houseData[0]))%360}for(let i=0;i<12;i++){let r;r=this.houseData&&this.houseData.length>=12?this.getHouseLongitude(this.houseData[i]):30*i;const a=((r+n+t)%360+15)%360,c=this.svgUtils.pointOnCircle(this.centerX,this.centerY,this.numberRadius,a),l=this.svgUtils.createSVGElement("text",{x:c.x,y:c.y,class:"house-element house-number"});a>=315||a<45?(l.setAttribute("text-anchor","middle"),l.setAttribute("dominant-baseline","auto")):a>=45&&a<135?(l.setAttribute("text-anchor","start"),l.setAttribute("dominant-baseline","middle")):a>=135&&a<225?(l.setAttribute("text-anchor","middle"),l.setAttribute("dominant-baseline","hanging")):(l.setAttribute("text-anchor","end"),l.setAttribute("dominant-baseline","middle")),l.textContent=o.houseToRoman(i+1),this.svgUtils.addTooltip(l,`House ${i+1}`),e.appendChild(l),s.push(l)}return s}getHouseLongitude(e){return null==e?(console.warn("HouseRenderer: Null or undefined house data"),0):"object"==typeof e&&null!==e&&"lon"in e?e.lon:"number"==typeof e?e:(console.warn("HouseRenderer: Unrecognized house data format",e),0)}}class l extends r{constructor(e){if(super(e),!e.assetBasePath)throw new Error(`${this.constructor.name}: Missing required option assetBasePath`);this.iconProvider=e.iconProvider}calculateBasePositions(e,t,s){e.forEach((e=>{const n=(e.position-90)*(Math.PI/180);e.radians=n;const i=this.svgUtils.pointOnCircle(this.centerX,this.centerY,t,e.position);e.x=i.x,e.y=i.y;const r=this.svgUtils.pointOnCircle(this.centerX,this.centerY,s,e.position);e.iconX=r.x,e.iconY=r.y,e.adjustedIconX=e.iconX,e.adjustedIconY=e.iconY}))}preparePlanetData(e,t,s,n){return e.map((e=>({...e,name:e.name||"unknown",position:void 0!==e.position?e.position:0,x:0,y:0,iconX:0,iconY:0,adjustedIconX:0,adjustedIconY:0,radians:0,zodiacSign:o.getZodiacSigns()[Math.floor(e.position/30)%12],position_in_sign:e.position%30,isPrimary:"primary"===t,type:t,color:e.color||"#000000",dotRadius:s,iconRadius:n})))}render(e,t,s=0,n={}){throw new Error(`${this.constructor.name}: render() not implemented.`)}}class h extends l{constructor(e){super(e)}renderPlanetSymbol(e,t,s=24){let n;n=this.iconProvider?this.iconProvider.getPlanetIconPath(t.name):`${this.options.assetBasePath}svg/zodiac/zodiac-planet-${t.name.toLowerCase()}.svg`;const i=t.adjustedIconX-s/2,r=t.adjustedIconY-s/2,o=t.isPrimary?"primary":"secondary",a=this.svgUtils.createSVGElement("image",{x:i,y:r,width:s,height:s,href:n,class:`planet-icon planet-${t.name}-icon planet-${o}-icon`});return a.addEventListener("error",(()=>{console.warn(`Planet icon not found: ${n}`),a.setAttribute("href","");const i=t.name.charAt(0).toUpperCase();let r;this.iconProvider?r=this.iconProvider.createTextFallback(this.svgUtils,{x:t.adjustedIconX,y:t.adjustedIconY,size:`${s}px`,color:t.color||"#000000",className:`planet-symbol planet-${t.name}-symbol planet-${o}-symbol`},i):(r=this.svgUtils.createSVGElement("text",{x:t.adjustedIconX,y:t.adjustedIconY,"text-anchor":"middle","dominant-baseline":"middle","font-size":`${s}px`,class:`planet-symbol planet-${t.name}-symbol planet-${o}-symbol`,fill:t.color||"#000000"}),r.textContent=t.name.charAt(0).toUpperCase()),e.appendChild(r)})),a}renderPlanetDot(e,t,s=3){const n=t.isPrimary?"primary":"secondary";return this.svgUtils.createSVGElement("circle",{cx:t.x,cy:t.y,r:s,class:`planet-dot planet-${t.name}-dot planet-${n}-dot`,fill:t.color||"#000000"})}renderConnector(e,t,s,n=.3){const i=t.isPrimary?"primary":"secondary",r=t.x-t.adjustedIconX,o=t.y-t.adjustedIconY;if(Math.sqrt(r*r+o*o)>s*n){return this.svgUtils.createSVGElement("line",{x1:t.x,y1:t.y,x2:t.adjustedIconX,y2:t.adjustedIconY,class:`planet-element planet-${t.name.toLowerCase()} planet-connector planet-${i}-connector`,stroke:t.color||"#000000","stroke-width":.75,"stroke-opacity":.5})}return null}addPlanetTooltip(e,t){const s=`${t.isPrimary?"Primary":"Secondary"} ${o.getPlanetFullName(t.name)}: ${t.position.toFixed(1)}° ${t.zodiacSign.toUpperCase()} (${t.position_in_sign.toFixed(1)}°)`;this.svgUtils.addTooltip(e,s)}render(e,t,s=0,n={}){throw new Error(`${this.constructor.name}: This is a utility renderer, use specific rendering methods instead.`)}}class d{static calculatePosition(e){const{centerX:t,centerY:s,radius:i,longitude:r,iconSize:o=24}=e,a=(new n).pointOnCircle(t,s,i,r),c=a.x-o/2,l=a.y-o/2;return{x:a.x,y:a.y,iconX:c,iconY:l,iconCenterX:a.x,iconCenterY:a.y,longitude:r,radius:i}}static detectOverlaps(e,t=24){const s=[],n=new Set;for(let i=0;i<e.length;i++){if(n.has(i))continue;const r=[i];n.add(i);for(let s=0;s<e.length;s++){if(i===s||n.has(s))continue;Math.sqrt(Math.pow(e[i].x-e[s].x,2)+Math.pow(e[i].y-e[s].y,2))<t&&(r.push(s),n.add(s))}r.length>1&&s.push(r)}return s}static adjustOverlaps(e,t={}){const{minDistance:s=24,centerX:n,centerY:i,baseRadius:r,iconSize:o=24}=t;if(!e||e.length<=1)return e;if(!n||!i||!r)return console.error("PlanetPositionCalculator: Missing required parameters (centerX, centerY, or baseRadius)"),e;console.log(`PlanetPositionCalculator: Adjusting overlaps for ${e.length} positions`);const a=[...e],c=s/r*(180/Math.PI);console.log(`PlanetPositionCalculator: Minimum angular distance: ${c.toFixed(2)}°`);const l=a.map(((e,t)=>({pos:e,idx:t}))).sort(((e,t)=>e.pos.longitude-t.pos.longitude)).map((e=>({...a[e.idx],originalIndex:e.idx}))),h=this._findOverlappingClusters(l,c);return console.log(`PlanetPositionCalculator: Found ${h.length} clusters of overlapping positions`),h.forEach(((e,t)=>{console.log(`PlanetPositionCalculator: Cluster ${t+1} has ${e.length} positions`)})),h.forEach(((e,t)=>{if(console.log(`PlanetPositionCalculator: Processing cluster ${t+1}`),e.length<=1){const t=e[0];console.log(`PlanetPositionCalculator: Single position in cluster, keeping at original longitude ${t.longitude.toFixed(2)}°`),this._setExactPosition(t,t.longitude,r,n,i,o)}else console.log(`PlanetPositionCalculator: Distributing ${e.length} positions in cluster`),this._distributeClusterByAngle(e,r,c,n,i,o),e.forEach(((e,s)=>{console.log(`PlanetPositionCalculator: Position ${s+1} in cluster ${t+1} adjusted from ${e.longitude.toFixed(2)}° to ${e.adjustedLongitude.toFixed(2)}°`)}))})),l.forEach((e=>{const t=e.originalIndex;void 0!==t&&t>=0&&t<a.length&&(a[t].x=e.x,a[t].y=e.y,a[t].iconX=e.iconX,a[t].iconY=e.iconY,a[t].iconCenterX=e.iconCenterX,a[t].iconCenterY=e.iconCenterY,void 0!==e.adjustedLongitude&&(a[t].adjustedLongitude=e.adjustedLongitude))})),a}static _findOverlappingClusters(e,t){if(!e.length)return[];if(1===e.length)return[e];const s=[];let n=[e[0]];const i=e.length;e[0],e[0].longitude;for(let r=1;r<i;r++){const i=e[r-1],o=e[r];let a=o.longitude-i.longitude;a<0&&(a+=360),a<t?n.push(o):(n.length>0&&s.push(n),n=[o])}n.length>0&&s.push(n);const r=e[i-1],o=e[0];let a=o.longitude+360-r.longitude;if(a<0&&(a+=360),a<t&&s.length>=2){const e=s[0],t=s[s.length-1];if(e.includes(o)&&t.includes(r)){const n=[...t,...e];s.pop(),s[0]=n}}return s}static _distributeClusterByAngle(e,t,s,n,i,r){const o=e.length;e.sort(((e,t)=>e.longitude-t.longitude));const a=e[0].longitude,c=e[o-1].longitude;let l=c-a;(l<0||l>180)&&(l=(360+c-a)%360);let h=(a+l/2)%360;const d=(o-1)*s,u=Math.max(l,d),g=(h-u/2+360)%360;for(let s=0;s<o;s++){if(1===o){this._setExactPosition(e[s],e[s].longitude,t,n,i,r);continue}const a=(g+s*(u/(o-1)))%360;this._setExactPosition(e[s],a,t,n,i,r)}}static _setExactPosition(e,t,s,i,r,o){const a=(new n).pointOnCircle(i,r,s,t);e.x=a.x,e.y=a.y,e.iconCenterX=a.x,e.iconCenterY=a.y,e.iconX=a.x-o/2,e.iconY=a.y-o/2,e.adjustedLongitude=t}}class u extends l{constructor(e){super(e),this.symbolRenderer=e.symbolRenderer,this.circleConfig={circle:"inner"}}calculateRadii(e=null){const t=e?.radius?.inner||this.innerRadius;return{dotRadius:t,iconRadius:t+((e?.radius?.middle||this.middleRadius)-t)/2}}adjustOverlappingPlanets(e){if(e.length<=1)return;const t=e[0].iconRadius,s=24*1.2,n=e.map(((e,s)=>({x:e.iconX,y:e.iconY,iconX:e.iconX,iconY:e.iconY,iconCenterX:e.iconX,iconCenterY:e.iconY,longitude:e.position,radius:t,originalIndex:s,name:e.name})));d.adjustOverlaps(n,{minDistance:s,centerX:this.centerX,centerY:this.centerY,baseRadius:t,iconSize:24}).forEach(((t,s)=>{const n=e[s];n.position,n.adjustedIconX=t.iconCenterX,n.adjustedIconY=t.iconCenterY,void 0!==t.adjustedLongitude&&(n.adjustedPosition=t.adjustedLongitude)}))}render(e,t,s=0,n={}){if(!e)return console.error("PrimaryPlanetRenderer: parentGroup is null or undefined."),[];const{dotRadius:i,iconRadius:r}=n.dotRadius&&n.iconRadius?{dotRadius:n.dotRadius,iconRadius:n.iconRadius}:this.calculateRadii(n.config||this.config);if(!i||!r)return console.error("PrimaryPlanetRenderer: Could not determine radius values"),[];this.clearGroup(e);const o=this.preparePlanetData(t,"primary",i,r);return o.sort(((e,t)=>e.position-t.position)),this.calculateBasePositions(o,i,r),this.adjustOverlappingPlanets(o),this.drawPlanets(e,o),o}drawPlanets(e,t){t.forEach((t=>{const s=this.svgUtils.createSVGElement("g",{"data-planet":t.name,"data-type":t.type,class:`planet-element planet-${t.name} planet-primary`,transform:"translate(0,0)"}),n=this.symbolRenderer.renderPlanetDot(s,t);s.appendChild(n);const i=this.symbolRenderer.renderPlanetSymbol(s,t,24);s.appendChild(i),this.symbolRenderer.addPlanetTooltip(s,t);const r=this.symbolRenderer.renderConnector(s,t,24);r&&s.appendChild(r),e.appendChild(s)}))}}class g extends l{constructor(e){super(e),this.symbolRenderer=e.symbolRenderer,this.circleConfig={circle:"innermost"}}calculateRadii(e=null){const t=e?.radius?.innermost||.5*this.innerRadius;return{dotRadius:t,iconRadius:t+((e?.radius?.zodiacInner||this.innerRadius)-t)/2}}adjustOverlappingPlanets(e){if(e.length<=1)return;const t=e[0].iconRadius,s=e.map(((e,s)=>({x:e.iconX,y:e.iconY,iconX:e.iconX,iconY:e.iconY,iconCenterX:e.iconX,iconCenterY:e.iconY,longitude:e.position,radius:t,originalIndex:s,name:e.name})));d.adjustOverlaps(s,{minDistance:19.8,centerX:this.centerX,centerY:this.centerY,baseRadius:t,iconSize:18}).forEach(((t,s)=>{const n=e[s];n.adjustedIconX=t.iconCenterX,n.adjustedIconY=t.iconCenterY,void 0!==t.adjustedLongitude&&(n.adjustedPosition=t.adjustedLongitude)}))}render(e,t,s=0,n={}){if(!e)return console.error("SecondaryPlanetRenderer: parentGroup is null or undefined."),[];const{dotRadius:i,iconRadius:r}=n.dotRadius&&n.iconRadius?{dotRadius:n.dotRadius,iconRadius:n.iconRadius}:this.calculateRadii(n.config||this.config);if(!i||!r)return console.error("SecondaryPlanetRenderer: Could not determine radius values"),[];this.clearGroup(e);const o=this.preparePlanetData(t,"secondary",i,r);return o.sort(((e,t)=>e.position-t.position)),this.calculateBasePositions(o,i,r),this.adjustOverlappingPlanets(o),this.drawPlanets(e,o),o}drawPlanets(e,t){t.forEach((t=>{const s=this.svgUtils.createSVGElement("g",{"data-planet":t.name,"data-type":t.type,class:`planet-element planet-${t.name} planet-secondary`,transform:"translate(0,0)"}),n=this.symbolRenderer.renderPlanetDot(s,t,2);s.appendChild(n);const i=this.symbolRenderer.renderPlanetSymbol(s,t,18);s.appendChild(i),this.symbolRenderer.addPlanetTooltip(s,t);const r=this.symbolRenderer.renderConnector(s,t,18);r&&s.appendChild(r),e.appendChild(s)}))}}class p extends l{constructor(e){super(e),this.primaryRenderer=e.primaryRenderer,this.secondaryRenderer=e.secondaryRenderer,this.symbolRenderer=e.symbolRenderer,this.circleConfigs={primary:{circle:"inner"},secondary:{circle:"innermost"}}}calculateRadii(e,t=null){if(!this.circleConfigs[e])return console.error(`PlanetRendererCoordinator: No circle configuration found for planet type: ${e}`),{dotRadius:null,iconRadius:null};switch(e){case"primary":return this.primaryRenderer.calculateRadii(t);case"secondary":return this.secondaryRenderer.calculateRadii(t);default:return console.error(`PlanetRendererCoordinator: Unknown planet type: ${e}`),{dotRadius:null,iconRadius:null}}}render(e,t,s=0,n={}){const i=n.type||"primary";switch(console.log(`PlanetRendererCoordinator: Rendering ${i} planets, count:`,t.length),i){case"primary":return this.primaryRenderer.render(e,t,s,n);case"secondary":return this.secondaryRenderer.render(e,t,s,n);default:return console.error(`PlanetRendererCoordinator: Unknown planet type: ${i}`),[]}}renderAllPlanetTypes(e){const{svgManager:t,planetsData:s,config:n,enabledTypes:i={primary:!0,secondary:!0}}=e;if(!t||!s||!n)return console.error("PlanetRendererCoordinator: Missing required parameters"),{};const r=Object.entries(s).filter((([e,t])=>!1!==n.planetSettings.visible?.[e])).map((([e,t])=>({name:e,position:t.lon,color:t.color||"#000000"}))),o={},a=this.centerX,c=this.centerY;if(this.centerX=n.svg.center.x,this.centerY=n.svg.center.y,this.primaryRenderer.centerX=this.centerX,this.primaryRenderer.centerY=this.centerY,this.secondaryRenderer.centerX=this.centerX,this.secondaryRenderer.centerY=this.centerY,i.primary){const e=t.getGroup("primaryPlanets");o.primary=this.primaryRenderer.render(e,r,0,{config:n}),console.log(`PlanetRendererCoordinator: Rendered ${o.primary.length} primary planets`)}else o.primary=[];if(i.secondary){const e=t.getGroup("secondaryPlanets");o.secondary=this.secondaryRenderer.render(e,r,0,{config:n}),console.log(`PlanetRendererCoordinator: Rendered ${o.secondary.length} secondary planets`)}else o.secondary=[];return this.centerX=a,this.centerY=c,this.primaryRenderer.centerX=a,this.primaryRenderer.centerY=c,this.secondaryRenderer.centerX=a,this.secondaryRenderer.centerY=c,o}renderAllPlanets(e){return console.warn("PlanetRendererCoordinator: renderAllPlanets is deprecated, use renderAllPlanetTypes instead"),this.renderAllPlanetTypes(e)}}class y extends r{constructor(e){super(e),this.astrologyUtils=o,this.renderedAspects=[],this._aspectCacheKey=null,this._aspectCache=[],this.assetBasePath=e.assetBasePath||"",this.iconProvider=e.iconProvider,this.defaultAspectDefinitions={conjunction:{angle:0,orb:8,color:"#FF4500",abbr:"CON"},opposition:{angle:180,orb:6,color:"#DC143C",abbr:"OPP"},trine:{angle:120,orb:6,color:"#2E8B57",abbr:"TRI"},square:{angle:90,orb:6,color:"#FF0000",abbr:"SQR"},sextile:{angle:60,orb:4,color:"#4682B4",abbr:"SEX"}}}_angularDistance(e,t){const s=Math.abs(e-t)%360;return Math.min(s,360-s)}calculateAspects(e){const t=[];if(!e||e.length<2)return t;const s=`${JSON.stringify(this.config.aspectSettings)}|${e.map((e=>`${e.name}:${e.position}`)).join("|")}`;if(s===this._aspectCacheKey)return console.log(`ClientSideAspectRenderer: Using cached aspects (${this._aspectCache.length})`),this._aspectCache;const n=this.config.aspectSettings||{},i=n.orb||6,r=n.types||this.defaultAspectDefinitions;for(let s=0;s<e.length;s++)for(let n=s+1;n<e.length;n++){const o=e[s],a=e[n],c=this._angularDistance(o.position,a.position);for(const e in r){const s=r[e],n=s.angle,l=void 0!==s.orb?s.orb:i;Math.abs(c-n)<=l&&t.push({planet1:o.name,planet2:a.name,type:e,angle:n,angleDiff:c,orb:Math.abs(c-n),p1:o,p2:a,color:s.color||"#888",lineStyle:s.lineStyle,abbr:s.abbr||e.substring(0,3).toUpperCase()})}}return console.log(`ClientSideAspectRenderer: Calculated ${t.length} aspects.`),this._aspectCacheKey=s,this._aspectCache=t,t}render(e,t){if(!e)return console.error("ClientSideAspectRenderer.render: parentGroup is null or undefined."),[];this.clearGroup(e);const s=[];if(!t||t.length<2)return console.warn("ClientSideAspectRenderer: Not enough planet data with coordinates to render aspects."),this.renderedAspects=[],[];const n=this.calculateAspects(t);this.renderedAspects=n,console.log(`ClientSideAspectRenderer: Rendering ${n.length} aspects.`);const i=(this.config.aspectSettings||{}).types||{},r={};return t.forEach((e=>{r[e.name]={x:e.x,y:e.y}})),n.forEach((t=>{const n=r[t.planet1],o=r[t.planet2],a=i[t.type],c=!a||!1!==a.enabled,l=a?a.lineStyle:"solid";if(!c||"none"===l)return;if(!n||!o)return void console.warn(`ClientSideAspectRenderer: Could not find coordinates for aspect: ${t.planet1} ${t.type} ${t.planet2}`);const h=(t.planet1||"").toLowerCase().replace(/[^a-z0-9]/g,"-"),d=(t.planet2||"").toLowerCase().replace(/[^a-z0-9]/g,"-");let u="none";"dashed"===l?u="5, 5":"dotted"===l&&(u="1, 3");const g=this.svgUtils.createSVGElement("line",{x1:n.x,y1:n.y,x2:o.x,y2:o.y,class:`aspect-element aspect-line aspect-${t.type} aspect-planet-${h} aspect-planet-${d}`,stroke:t.color||"#888888","stroke-dasharray":u}),p=`${this.astrologyUtils.capitalizeFirstLetter(t.planet1)} ${t.type} ${this.astrologyUtils.capitalizeFirstLetter(t.planet2)} (${t.angleDiff.toFixed(1)}°, orb ${t.orb.toFixed(1)}°)`;this.svgUtils.addTooltip(g,p),e.appendChild(g),s.push(g),this._addAspectIcon(e,t,n,o,p)})),s}clearGroup(e){super.clearGroup(e)}getCurrentAspects(){return this.renderedAspects}_addAspectIcon(e,t,s,n,i){const r=(s.x+n.x)/2,o=(s.y+n.y)/2,a=r-this.centerX,c=o-this.centerY;if(Math.sqrt(a*a+c*c)<20)return;let l;l=this.iconProvider?this.iconProvider.getAspectIconPath(t.type):`${this.assetBasePath}/svg/zodiac/zodiac-aspect-${t.type}.svg`;const h=this.svgUtils.createSVGElement("image",{x:r-8,y:o-8,width:16,height:16,href:l,class:`aspect-element aspect-symbol aspect-${t.type}`});h.addEventListener("error",(()=>{console.warn(`Failed to load aspect icon for ${t.type} from path: ${l}`);const s=this.defaultAspectDefinitions[t.type],n=s&&s.abbr?s.abbr:t.type.substring(0,3).toUpperCase();let a;this.iconProvider?a=this.iconProvider.createTextFallback(this.svgUtils,{x:r,y:o,size:"12px",color:t.color||"#888888",className:`aspect-element aspect-symbol aspect-${t.type}`},n):(a=this.svgUtils.createSVGElement("text",{x:r,y:o,"text-anchor":"middle","dominant-baseline":"middle","font-size":"12px","font-weight":"bold",class:`aspect-element aspect-symbol aspect-${t.type}`,fill:t.color||"#888888"}),a.textContent=n),this.svgUtils.addTooltip(a,i),e.appendChild(a)})),this.svgUtils.addTooltip(h,i),e.appendChild(h)}}class m{constructor(e,s){this.config=e,this.svgNS=s,this.svgUtils=t.getSvgUtils(),this.iconProvider=t.getIconProvider(e.assets?.basePath)}createZodiacRenderer(e={}){return new a({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,...e})}createHouseRenderer(e={}){return new c({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,...e})}createPlanetRenderer(e={}){const t=new h({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,assetBasePath:e.assetBasePath||this.config.assets?.basePath,...e}),s=new u({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,symbolRenderer:t,assetBasePath:e.assetBasePath||this.config.assets?.basePath,...e}),n=new g({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,symbolRenderer:t,assetBasePath:e.assetBasePath||this.config.assets?.basePath,...e});return new p({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,primaryRenderer:s,secondaryRenderer:n,symbolRenderer:t,assetBasePath:e.assetBasePath||this.config.assets?.basePath,...e})}createAspectRenderer(e={}){return new y({svgNS:this.svgNS,config:this.config,svgUtils:this.svgUtils,iconProvider:this.iconProvider,...e})}}class f{constructor(e){this.config=e.config,this.svgManager=e.svgManager,this.planets=e.planets||{},this.houses=e.houses||[],this.renderers={},this.svgManager&&this.svgManager.getSVG()&&this._initializeRenderers()}_initializeRenderers(){this.rendererFactory=new m(this.config,this.svgManager.svgNS),this.renderers.zodiac=this.rendererFactory.createZodiacRenderer({assetBasePath:this.config.assets.basePath});const e=this.config.getHouseCusps(),t=e&&e.length>0?e:this.houses;this.renderers.house=this.rendererFactory.createHouseRenderer({houseData:t}),this.renderers.planet=this.rendererFactory.createPlanetRenderer({assetBasePath:this.config.assets.basePath}),this.renderers.aspect=this.rendererFactory.createAspectRenderer({assetBasePath:this.config.assets.basePath})}updatePlanets(e){this.planets=e}updateHouses(e){this.houses=e,this.renderers.house&&(this.renderers.house.houseData=this.houses)}renderAll(){if(!this.svgManager.getSVG())return;Object.values(this.svgManager.getAllGroups()).forEach((e=>{e.innerHTML=""})),this.renderZodiac(),this.renderHouses();const e=this.renderPlanets();this.renderAspects(e),console.log("RenderingCoordinator: Chart rendered")}renderZodiac(){return!(!this.config.zodiacSettings.enabled||!this.renderers.zodiac)&&(this.renderers.zodiac.render(this.svgManager.getGroup("zodiac")),!0)}renderHouses(){if(!this.config.houseSettings.enabled||!this.renderers.house)return!1;const e=this.svgManager.getGroup("houses"),t=this.svgManager.getGroup("houseDivisions"),s=this.config.getHouseCusps();return s&&s.length>0&&(this.renderers.house.houseData=s),this.renderers.house.renderDivisions(t,this.config.houseSettings.rotationAngle),this.renderers.house.renderNumbers(e,this.config.houseSettings.rotationAngle),!0}renderPlanets(){if(!this.config.planetSettings.enabled||!this.renderers.planet)return[];const e=!1!==this.config.planetSettings.primaryEnabled,t=!1!==this.config.planetSettings.secondaryEnabled,s=this.renderers.planet.renderAllPlanetTypes({svgManager:this.svgManager,planetsData:this.planets,config:this.config,primaryEnabled:e,secondaryEnabled:t});return console.log(`RenderingCoordinator: Rendered ${s.primary.length} primary planets and ${s.secondary.length} secondary planets`),s.primary}renderAspects(e){return!(!this.config.aspectSettings.enabled||!this.renderers.aspect)&&(this.renderers.aspect.render(this.svgManager.getGroup("aspects"),e),!0)}}class v{constructor(e){this.config=e.config,this.svgManager=e.svgManager}updateConfig(e){return this.config.mergeConfig(e),e.aspectSettings&&this.config.updateAspectSettings(e.aspectSettings),console.log("ChartStateManager: Updated configuration"),!0}togglePlanetVisibility(e,t){return this.config.togglePlanetVisibility(e,t),!0}toggleHousesVisibility(e){return this.config.toggleHousesVisibility(e),!0}toggleAspectsVisibility(e){return this.config.toggleAspectsVisibility(e),!0}setHouseRotation(e){return this.config.houseSettings.rotationAngle=e,!0}setHouseSystem(e){return this.config.setHouseSystem(e)}getAvailableHouseSystems(){return this.config.getAvailableHouseSystems()}getCurrentHouseSystem(){return this.config.getHouseSystem()}togglePrimaryPlanets(e){if(this.config.togglePrimaryPlanetsVisibility(e),this.svgManager){const t=this.svgManager.getGroup("primaryPlanets");t&&(t.style.display=e?"block":"none")}return console.log("ChartStateManager: Primary planets "+(e?"enabled":"disabled")),!0}toggleSecondaryPlanets(e){if(this.config.toggleSecondaryPlanetsVisibility(e),this.svgManager){const t=this.svgManager.getGroup("secondaryPlanets");t&&(t.style.display=e?"block":"none");const s=document.querySelector(".chart-innermost-circle");s&&(s.style.display=e?"block":"none")}return console.log("ChartStateManager: Secondary planets "+(e?"enabled":"disabled")),!0}}class S{constructor(e){if(!e||!e.container)throw new Error("ChartManager: Container element or selector is required");if(this.options=e,this.container="string"==typeof e.container?document.querySelector(e.container):e.container,!this.container)throw new Error(`ChartManager: Container not found: ${e.container}`);this.config=new s(e.config||{}),this.planets=e.planets||{},this.houses=e.houses||[],e.aspectSettings&&this.config.updateAspectSettings(e.aspectSettings),t.initializeServices();const n=t.getSvgUtils();this.svgManager=new i({svgUtils:n}),this.renderingCoordinator=new f({config:this.config,svgManager:this.svgManager,planets:this.planets,houses:this.houses}),this.stateManager=new v({config:this.config,svgManager:this.svgManager}),console.log("ChartManager: Initialized")}_initialize(){const e={width:this.config.svg.width,height:this.config.svg.height,viewBox:this.config.svg.viewBox};this.svgManager.initialize(this.container,e),this.svgManager.createStandardGroups()}render(){return this.svgManager.getSVG()||this._initialize(),this.renderingCoordinator.renderAll(),console.log("ChartManager: Chart rendered"),this}update(e){return e.planets&&(this.planets=e.planets,this.renderingCoordinator.updatePlanets(this.planets)),e.houses&&(this.houses=e.houses,this.renderingCoordinator.updateHouses(this.houses)),e.config&&this.stateManager.updateConfig(e.config),this.render(),this}togglePlanet(e,t){return this.stateManager.togglePlanetVisibility(e,t),this.render(),this}toggleHouses(e){return this.stateManager.toggleHousesVisibility(e),this.render(),this}toggleAspects(e){return this.stateManager.toggleAspectsVisibility(e),this.render(),this}setHouseRotation(e){return this.stateManager.setHouseRotation(e),this.render(),this}destroy(){this.svgManager.getSVG()&&this.svgManager.getSVG().remove(),this.renderingCoordinator=null,this.stateManager=null,this.planets={},this.houses=[],console.log("ChartManager: Destroyed")}updateData(e){return e.planets&&("object"!=typeof e.planets||Array.isArray(e.planets)?console.warn("ChartManager.updateData: Invalid planets data format. Expected object."):(this.planets={...this.planets,...e.planets},this.renderingCoordinator.updatePlanets(this.planets),console.log("ChartManager: Updated planets data."))),e.houses&&(Array.isArray(e.houses)?(this.houses=e.houses,this.renderingCoordinator.updateHouses(this.houses),console.log("ChartManager: Updated houses data.")):console.warn("ChartManager.updateData: Invalid houses data format. Expected array.")),this.render(),this}updateConfig(e){return this.stateManager.updateConfig(e),console.log("ChartManager: Updated configuration."),this.render(),this}setHouseSystem(e){return this.stateManager.setHouseSystem(e),this.render(),this}getAvailableHouseSystems(){return this.stateManager.getAvailableHouseSystems()}getCurrentHouseSystem(){return this.stateManager.getCurrentHouseSystem()}togglePrimaryPlanets(e){return this.stateManager.togglePrimaryPlanets(e),this.render(),this}toggleSecondaryPlanets(e){return this.stateManager.toggleSecondaryPlanets(e),this.render(),this}}class b{constructor(e){if(!e||!e.container)throw new Error("NocturnaWheel: Container element or selector is required");if(this.options=e,this.container="string"==typeof e.container?document.querySelector(e.container):e.container,!this.container)throw new Error(`NocturnaWheel: Container not found: ${e.container}`);this.config=new s(e.config||{}),this.planets=e.planets||{},this.houses=e.houses||[],e.aspectSettings&&this.config.updateAspectSettings(e.aspectSettings),t.initializeServices();const n=t.getSvgUtils();this.svgManager=new i({svgUtils:n}),this.renderers={},console.log("NocturnaWheel: Initialized")}_initialize(){const e={width:this.config.svg.width,height:this.config.svg.height,viewBox:this.config.svg.viewBox};this.svgManager.initialize(this.container,e),this.svgManager.createStandardGroups(),this._initializeRenderers()}_initializeRenderers(){this.rendererFactory=new m(this.config,this.svgManager.svgNS),this.renderers.zodiac=this.rendererFactory.createZodiacRenderer({assetBasePath:this.config.assets.basePath});const e=this.config.getHouseCusps(),t=e&&e.length>0?e:this.houses;this.renderers.house=this.rendererFactory.createHouseRenderer({houseData:t}),this.renderers.planet=this.rendererFactory.createPlanetRenderer({assetBasePath:this.config.assets.basePath}),this.renderers.aspect=this.rendererFactory.createAspectRenderer({assetBasePath:this.config.assets.basePath})}render(){if(this.svgManager.getSVG()||this._initialize(),Object.values(this.svgManager.getAllGroups()).forEach((e=>{e.innerHTML=""})),this.config.zodiacSettings.enabled&&this.renderers.zodiac.render(this.svgManager.getGroup("zodiac")),this.config.houseSettings.enabled){const e=this.svgManager.getGroup("houses"),t=this.svgManager.getGroup("houseDivisions"),s=this.config.getHouseCusps();s&&s.length>0&&(this.renderers.house.houseData=s),this.renderers.house.renderDivisions(t,this.config.houseSettings.rotationAngle),this.renderers.house.renderNumbers(e,this.config.houseSettings.rotationAngle)}let e=[];if(this.config.planetSettings.enabled){const t=!1!==this.config.planetSettings.primaryEnabled,s=!1!==this.config.planetSettings.secondaryEnabled,n=this.renderers.planet.renderAllPlanetTypes({svgManager:this.svgManager,planetsData:this.planets,config:this.config,primaryEnabled:t,secondaryEnabled:s});e=n.primary,console.log(`NocturnaWheel: Rendered ${n.primary.length} primary planets and ${n.secondary.length} secondary planets`)}return this.config.aspectSettings.enabled&&this.renderers.aspect.render(this.svgManager.getGroup("aspects"),e),console.log("NocturnaWheel: Chart rendered"),this}update(e){return e.planets&&(this.planets=e.planets),e.houses&&(this.houses=e.houses,this.renderers.house&&(this.renderers.house.houseData=this.houses)),e.config&&this.config.mergeConfig(e.config),this.render(),this}togglePlanet(e,t){return this.config.togglePlanetVisibility(e,t),this.render(),this}toggleHouses(e){return this.config.toggleHousesVisibility(e),this.render(),this}toggleAspects(e){return this.config.toggleAspectsVisibility(e),this.render(),this}setHouseRotation(e){return this.config.houseSettings.rotationAngle=e,this.render(),this}destroy(){this.svgManager.getSVG()&&this.svgManager.getSVG().remove(),this.renderers={},this.planets={},this.houses=[],console.log("NocturnaWheel: Destroyed")}updateData(e){return e.planets&&("object"!=typeof e.planets||Array.isArray(e.planets)?console.warn("NocturnaWheel.updateData: Invalid planets data format. Expected object."):(this.planets={...this.planets,...e.planets},console.log("NocturnaWheel: Updated planets data."))),e.houses&&(Array.isArray(e.houses)?(this.houses=e.houses,this.renderers.house&&(this.renderers.house.houseData=this.houses),console.log("NocturnaWheel: Updated houses data.")):console.warn("NocturnaWheel.updateData: Invalid houses data format. Expected array.")),this.render(),this}updateConfig(e){return this.config.mergeConfig(e),e.aspectSettings&&this.config.updateAspectSettings(e.aspectSettings),console.log("NocturnaWheel: Updated configuration."),this.render(),this}setHouseSystem(e){return this.config.setHouseSystem(e),this.render(),this}getAvailableHouseSystems(){return this.config.getAvailableHouseSystems()}getCurrentHouseSystem(){return this.config.getHouseSystem()}togglePrimaryPlanets(e){this.config.togglePrimaryPlanetsVisibility(e);const t=this.svgManager.getGroup("primaryPlanets");return t&&(t.style.display=e?"block":"none"),console.log("NocturnaWheel: Primary planets "+(e?"enabled":"disabled")),this}toggleSecondaryPlanets(e){this.config.toggleSecondaryPlanetsVisibility(e);const t=this.svgManager.getGroup("secondaryPlanets");t&&(t.style.display=e?"block":"none");const s=document.querySelector(".chart-innermost-circle");return s&&(s.style.display=e?"block":"none"),console.log("NocturnaWheel: Secondary planets "+(e?"enabled":"disabled")),this}}class C{constructor(e,t={}){this.wheelChart=e,this.chart=e.chart,this.options=t,this.svgUtils=new n,console.log("ChartRenderer: Initialized with chart",this.chart)}renderInnerElements(){if(!this.chart||!this.chart.svgManager)return void console.error("ChartRenderer: Invalid chart or missing svgManager");if(!this.chart.svgManager.getSVG())return void console.error("ChartRenderer: SVG not found");const e=this.chart.svgManager.getGroup("zodiac");if(!e)return void console.error("ChartRenderer: Zodiac group not found");const t=e.querySelector(".chart-innermost-circle");t&&e.removeChild(t);const s=this.chart.config.svg.center.x,n=this.chart.config.svg.center.y,i=this.chart.config.radius.innermost;!1!==this.chart.config.planetSettings.secondaryEnabled&&this.drawInnermostCircle(e,this.svgUtils,s,n,i),console.log("ChartRenderer: Innermost circle rendered (if enabled). Planet rendering is now handled by NocturnaWheel.")}drawInnermostCircle(e,t,s,n,i){const r=t.createSVGElement("circle",{cx:s,cy:n,r:i,class:"zodiac-element chart-innermost-circle"});e.appendChild(r)}renderPlanets(e,t,s,n){return console.warn("ChartRenderer: renderPlanets is deprecated. Planet rendering is now handled by NocturnaWheel."),[]}drawPlanetsAndIcons(e,t,s,n,i){return console.warn("ChartRenderer: drawPlanetsAndIcons is deprecated, use renderPlanets instead"),this.renderPlanets(t,s,n,i)}drawPlanetDot(e,t,s,n,i,r){console.warn("ChartRenderer: drawPlanetDot is deprecated")}drawPlanetIcon(e,t,s,n,i){console.warn("ChartRenderer: drawPlanetIcon is deprecated")}drawConnector(e,t,s,n,i,r,o,a){console.warn("ChartRenderer: drawConnector is deprecated")}}class P{constructor(e,t=null){if(!e||!e.container)throw new Error("WheelChart: Container element or selector is required");this.options=e;const s=e.config||{};if("function"==typeof t?(console.log("WheelChart: Using provided chart factory function"),this.chart=t(e)):(console.log("WheelChart: Using default chart creation"),this.chart=new b({...e,config:s})),!this.chart||"function"!=typeof this.chart.render)throw new Error("WheelChart: Invalid chart instance created. Missing required methods.");this.renderer=new C(this,e),console.log("WheelChart: Initialized")}render(){return this.chart.render(),setTimeout((()=>{try{console.log("WheelChart: Rendering inner elements"),this.renderer.renderInnerElements()}catch(e){console.error("WheelChart: Error rendering inner elements:",e)}}),0),console.log("WheelChart: Chart rendered with inner circle"),this}update(e){return this.chart.update(e),this.renderer.renderInnerElements(),this}_delegateToChart(e,...t){if("function"==typeof this.chart[e])return this.chart[e](...t);throw new Error(`WheelChart: Method ${e} not