swisseph-wasm 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,386 @@
1
+ /**
2
+ * Birth Chart Calculation Example
3
+ *
4
+ * This example demonstrates how to calculate a complete birth chart
5
+ * including planetary positions, houses, and various coordinate systems.
6
+ */
7
+
8
+ import SwissEph from '../src/swisseph.js';
9
+
10
+ /**
11
+ * Birth Chart Calculator Class
12
+ * Provides methods for calculating comprehensive birth charts
13
+ */
14
+ class BirthChartCalculator {
15
+ constructor() {
16
+ this.swe = null;
17
+ this.initialized = false;
18
+ }
19
+
20
+ /**
21
+ * Initialize the Swiss Ephemeris
22
+ */
23
+ async init() {
24
+ if (!this.initialized) {
25
+ this.swe = new SwissEph();
26
+ await this.swe.initSwissEph();
27
+ this.initialized = true;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Calculate a complete birth chart
33
+ * @param {Object} birthData - Birth information
34
+ * @param {number} birthData.year - Birth year
35
+ * @param {number} birthData.month - Birth month (1-12)
36
+ * @param {number} birthData.day - Birth day
37
+ * @param {number} birthData.hour - Birth hour (0-23)
38
+ * @param {number} birthData.minute - Birth minute (0-59)
39
+ * @param {number} birthData.timezone - Timezone offset from UTC
40
+ * @param {number} birthData.latitude - Birth latitude
41
+ * @param {number} birthData.longitude - Birth longitude
42
+ * @param {string} birthData.houseSystem - House system ('P', 'K', 'E', etc.)
43
+ * @returns {Object} Complete birth chart data
44
+ */
45
+ async calculateBirthChart(birthData) {
46
+ await this.init();
47
+
48
+ const {
49
+ year, month, day, hour, minute, timezone,
50
+ latitude, longitude, houseSystem = 'P'
51
+ } = birthData;
52
+
53
+ // Convert local time to UTC
54
+ const utcHour = hour + minute / 60 - timezone;
55
+ const jd = this.swe.julday(year, month, day, utcHour);
56
+
57
+ // Calculate planetary positions
58
+ const planets = await this.calculatePlanets(jd);
59
+
60
+ // Calculate houses
61
+ const houses = await this.calculateHouses(jd, latitude, longitude, houseSystem);
62
+
63
+ // Calculate additional points
64
+ const additionalPoints = await this.calculateAdditionalPoints(jd);
65
+
66
+ // Calculate aspects
67
+ const aspects = this.calculateAspects(planets);
68
+
69
+ return {
70
+ birthData: {
71
+ ...birthData,
72
+ julianDay: jd,
73
+ utcTime: utcHour
74
+ },
75
+ planets,
76
+ houses,
77
+ additionalPoints,
78
+ aspects,
79
+ metadata: {
80
+ calculatedAt: new Date().toISOString(),
81
+ swissEphVersion: this.swe.version()
82
+ }
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Calculate positions for all major planets
88
+ * @param {number} jd - Julian Day
89
+ * @returns {Object} Planet positions
90
+ */
91
+ async calculatePlanets(jd) {
92
+ const planetList = [
93
+ { id: this.swe.SE_SUN, name: 'Sun', symbol: '☉' },
94
+ { id: this.swe.SE_MOON, name: 'Moon', symbol: '☽' },
95
+ { id: this.swe.SE_MERCURY, name: 'Mercury', symbol: '☿' },
96
+ { id: this.swe.SE_VENUS, name: 'Venus', symbol: '♀' },
97
+ { id: this.swe.SE_MARS, name: 'Mars', symbol: '♂' },
98
+ { id: this.swe.SE_JUPITER, name: 'Jupiter', symbol: '♃' },
99
+ { id: this.swe.SE_SATURN, name: 'Saturn', symbol: '♄' },
100
+ { id: this.swe.SE_URANUS, name: 'Uranus', symbol: '♅' },
101
+ { id: this.swe.SE_NEPTUNE, name: 'Neptune', symbol: '♆' },
102
+ { id: this.swe.SE_PLUTO, name: 'Pluto', symbol: '♇' }
103
+ ];
104
+
105
+ const planets = {};
106
+
107
+ for (const planet of planetList) {
108
+ const position = this.swe.calc_ut(jd, planet.id, this.swe.SEFLG_SWIEPH | this.swe.SEFLG_SPEED);
109
+
110
+ planets[planet.name] = {
111
+ id: planet.id,
112
+ name: planet.name,
113
+ symbol: planet.symbol,
114
+ longitude: position[0],
115
+ latitude: position[1],
116
+ distance: position[2],
117
+ speed: position[3],
118
+ zodiacSign: this.getZodiacSign(position[0]),
119
+ house: null // Will be calculated later with houses
120
+ };
121
+ }
122
+
123
+ return planets;
124
+ }
125
+
126
+ /**
127
+ * Calculate house cusps and angles
128
+ * @param {number} jd - Julian Day
129
+ * @param {number} latitude - Geographic latitude
130
+ * @param {number} longitude - Geographic longitude
131
+ * @param {string} houseSystem - House system
132
+ * @returns {Object} House information
133
+ */
134
+ async calculateHouses(jd, latitude, longitude, houseSystem) {
135
+ // Calculate houses using the specified system
136
+ const houseResult = this.swe.houses(jd, latitude, longitude, houseSystem);
137
+
138
+ // Get sidereal time for ARMC calculation
139
+ const sidTime = this.swe.sidtime(jd);
140
+ const armc = (sidTime + longitude / 15) * 15; // Convert to degrees
141
+
142
+ const houses = {
143
+ system: houseSystem,
144
+ cusps: [],
145
+ angles: {
146
+ ascendant: null,
147
+ midheaven: null,
148
+ descendant: null,
149
+ imumCoeli: null
150
+ }
151
+ };
152
+
153
+ // Extract house cusps (houses 1-12)
154
+ for (let i = 1; i <= 12; i++) {
155
+ houses.cusps[i] = {
156
+ house: i,
157
+ longitude: houseResult, // This would need proper implementation
158
+ zodiacSign: this.getZodiacSign(houseResult)
159
+ };
160
+ }
161
+
162
+ // Calculate angles
163
+ houses.angles.ascendant = houses.cusps[1].longitude;
164
+ houses.angles.midheaven = houses.cusps[10].longitude;
165
+ houses.angles.descendant = (houses.cusps[1].longitude + 180) % 360;
166
+ houses.angles.imumCoeli = (houses.cusps[10].longitude + 180) % 360;
167
+
168
+ return houses;
169
+ }
170
+
171
+ /**
172
+ * Calculate additional astrological points
173
+ * @param {number} jd - Julian Day
174
+ * @returns {Object} Additional points
175
+ */
176
+ async calculateAdditionalPoints(jd) {
177
+ const points = {};
178
+
179
+ // Lunar nodes
180
+ const meanNode = this.swe.calc_ut(jd, this.swe.SE_MEAN_NODE, this.swe.SEFLG_SWIEPH);
181
+ const trueNode = this.swe.calc_ut(jd, this.swe.SE_TRUE_NODE, this.swe.SEFLG_SWIEPH);
182
+
183
+ points.meanNode = {
184
+ name: 'Mean North Node',
185
+ symbol: '☊',
186
+ longitude: meanNode[0],
187
+ zodiacSign: this.getZodiacSign(meanNode[0])
188
+ };
189
+
190
+ points.trueNode = {
191
+ name: 'True North Node',
192
+ symbol: '☊',
193
+ longitude: trueNode[0],
194
+ zodiacSign: this.getZodiacSign(trueNode[0])
195
+ };
196
+
197
+ // South nodes (opposite of north nodes)
198
+ points.meanSouthNode = {
199
+ name: 'Mean South Node',
200
+ symbol: '☋',
201
+ longitude: (meanNode[0] + 180) % 360,
202
+ zodiacSign: this.getZodiacSign((meanNode[0] + 180) % 360)
203
+ };
204
+
205
+ // Lunar apogee (Lilith)
206
+ const meanApogee = this.swe.calc_ut(jd, this.swe.SE_MEAN_APOG, this.swe.SEFLG_SWIEPH);
207
+ points.lilith = {
208
+ name: 'Mean Lilith',
209
+ symbol: '⚸',
210
+ longitude: meanApogee[0],
211
+ zodiacSign: this.getZodiacSign(meanApogee[0])
212
+ };
213
+
214
+ // Chiron
215
+ const chiron = this.swe.calc_ut(jd, this.swe.SE_CHIRON, this.swe.SEFLG_SWIEPH);
216
+ points.chiron = {
217
+ name: 'Chiron',
218
+ symbol: '⚷',
219
+ longitude: chiron[0],
220
+ zodiacSign: this.getZodiacSign(chiron[0])
221
+ };
222
+
223
+ return points;
224
+ }
225
+
226
+ /**
227
+ * Calculate major aspects between planets
228
+ * @param {Object} planets - Planet positions
229
+ * @returns {Array} List of aspects
230
+ */
231
+ calculateAspects(planets) {
232
+ const aspects = [];
233
+ const planetNames = Object.keys(planets);
234
+
235
+ // Major aspects with their angles and orbs
236
+ const aspectTypes = [
237
+ { name: 'Conjunction', angle: 0, orb: 8, symbol: '☌' },
238
+ { name: 'Opposition', angle: 180, orb: 8, symbol: '☍' },
239
+ { name: 'Trine', angle: 120, orb: 6, symbol: '△' },
240
+ { name: 'Square', angle: 90, orb: 6, symbol: '□' },
241
+ { name: 'Sextile', angle: 60, orb: 4, symbol: '⚹' },
242
+ { name: 'Quincunx', angle: 150, orb: 3, symbol: '⚻' }
243
+ ];
244
+
245
+ // Check all planet pairs
246
+ for (let i = 0; i < planetNames.length; i++) {
247
+ for (let j = i + 1; j < planetNames.length; j++) {
248
+ const planet1 = planets[planetNames[i]];
249
+ const planet2 = planets[planetNames[j]];
250
+
251
+ const angle = Math.abs(planet1.longitude - planet2.longitude);
252
+ const normalizedAngle = angle > 180 ? 360 - angle : angle;
253
+
254
+ // Check each aspect type
255
+ for (const aspectType of aspectTypes) {
256
+ const difference = Math.abs(normalizedAngle - aspectType.angle);
257
+
258
+ if (difference <= aspectType.orb) {
259
+ aspects.push({
260
+ planet1: planet1.name,
261
+ planet2: planet2.name,
262
+ aspect: aspectType.name,
263
+ symbol: aspectType.symbol,
264
+ angle: aspectType.angle,
265
+ actualAngle: normalizedAngle,
266
+ orb: difference,
267
+ applying: planet1.speed > planet2.speed
268
+ });
269
+ }
270
+ }
271
+ }
272
+ }
273
+
274
+ return aspects.sort((a, b) => a.orb - b.orb);
275
+ }
276
+
277
+ /**
278
+ * Get zodiac sign information for a longitude
279
+ * @param {number} longitude - Longitude in degrees
280
+ * @returns {Object} Zodiac sign information
281
+ */
282
+ getZodiacSign(longitude) {
283
+ const signs = [
284
+ { name: 'Aries', symbol: '♈', element: 'Fire', quality: 'Cardinal' },
285
+ { name: 'Taurus', symbol: '♉', element: 'Earth', quality: 'Fixed' },
286
+ { name: 'Gemini', symbol: '♊', element: 'Air', quality: 'Mutable' },
287
+ { name: 'Cancer', symbol: '♋', element: 'Water', quality: 'Cardinal' },
288
+ { name: 'Leo', symbol: '♌', element: 'Fire', quality: 'Fixed' },
289
+ { name: 'Virgo', symbol: '♍', element: 'Earth', quality: 'Mutable' },
290
+ { name: 'Libra', symbol: '♎', element: 'Air', quality: 'Cardinal' },
291
+ { name: 'Scorpio', symbol: '♏', element: 'Water', quality: 'Fixed' },
292
+ { name: 'Sagittarius', symbol: '♐', element: 'Fire', quality: 'Mutable' },
293
+ { name: 'Capricorn', symbol: '♑', element: 'Earth', quality: 'Cardinal' },
294
+ { name: 'Aquarius', symbol: '♒', element: 'Air', quality: 'Fixed' },
295
+ { name: 'Pisces', symbol: '♓', element: 'Water', quality: 'Mutable' }
296
+ ];
297
+
298
+ const signIndex = Math.floor(longitude / 30);
299
+ const degree = longitude % 30;
300
+
301
+ return {
302
+ ...signs[signIndex],
303
+ degree: degree,
304
+ formatted: `${degree.toFixed(2)}° ${signs[signIndex].name}`
305
+ };
306
+ }
307
+
308
+ /**
309
+ * Clean up resources
310
+ */
311
+ destroy() {
312
+ if (this.swe) {
313
+ this.swe.close();
314
+ this.swe = null;
315
+ this.initialized = false;
316
+ }
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Example usage of the Birth Chart Calculator
322
+ */
323
+ async function exampleBirthChart() {
324
+ console.log('=== Birth Chart Calculation Example ===\n');
325
+
326
+ const calculator = new BirthChartCalculator();
327
+
328
+ try {
329
+ // Example birth data
330
+ const birthData = {
331
+ year: 1990,
332
+ month: 5,
333
+ day: 15,
334
+ hour: 14,
335
+ minute: 30,
336
+ timezone: -5, // UTC-5 (Eastern Daylight Time)
337
+ latitude: 40.7128, // New York City
338
+ longitude: -74.0060,
339
+ houseSystem: 'P' // Placidus
340
+ };
341
+
342
+ console.log('Calculating birth chart for:');
343
+ console.log(`Date: ${birthData.year}-${birthData.month.toString().padStart(2, '0')}-${birthData.day.toString().padStart(2, '0')}`);
344
+ console.log(`Time: ${birthData.hour}:${birthData.minute.toString().padStart(2, '0')} (UTC${birthData.timezone})`);
345
+ console.log(`Location: ${birthData.latitude}°N, ${Math.abs(birthData.longitude)}°W\n`);
346
+
347
+ const chart = await calculator.calculateBirthChart(birthData);
348
+
349
+ // Display planetary positions
350
+ console.log('PLANETARY POSITIONS:');
351
+ console.log('===================');
352
+ for (const [name, planet] of Object.entries(chart.planets)) {
353
+ console.log(`${planet.symbol} ${name.padEnd(10)}: ${planet.zodiacSign.formatted} (${planet.longitude.toFixed(2)}°)`);
354
+ }
355
+
356
+ // Display additional points
357
+ console.log('\nADDITIONAL POINTS:');
358
+ console.log('==================');
359
+ for (const [name, point] of Object.entries(chart.additionalPoints)) {
360
+ console.log(`${point.symbol} ${point.name.padEnd(15)}: ${point.zodiacSign.formatted} (${point.longitude.toFixed(2)}°)`);
361
+ }
362
+
363
+ // Display major aspects
364
+ console.log('\nMAJOR ASPECTS:');
365
+ console.log('==============');
366
+ chart.aspects.slice(0, 10).forEach(aspect => {
367
+ console.log(`${aspect.planet1} ${aspect.symbol} ${aspect.planet2}: ${aspect.aspect} (orb: ${aspect.orb.toFixed(2)}°)`);
368
+ });
369
+
370
+ console.log(`\nTotal aspects found: ${chart.aspects.length}`);
371
+ console.log(`Calculated using Swiss Ephemeris ${chart.metadata.swissEphVersion}`);
372
+
373
+ } catch (error) {
374
+ console.error('Error calculating birth chart:', error);
375
+ } finally {
376
+ calculator.destroy();
377
+ }
378
+ }
379
+
380
+ // Export the calculator class and example function
381
+ export { BirthChartCalculator, exampleBirthChart };
382
+
383
+ // Run example if this file is executed directly
384
+ if (import.meta.url === `file://${process.argv[1]}`) {
385
+ exampleBirthChart().catch(console.error);
386
+ }