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.
- package/DOCUMENTATION.md +888 -0
- package/LICENSE +41 -0
- package/QUICK_REFERENCE.md +263 -0
- package/README.md +305 -0
- package/examples/README.md +239 -0
- package/examples/basic-usage.js +301 -0
- package/examples/birth-chart.js +386 -0
- package/examples/demo.html +543 -0
- package/package.json +75 -0
- package/src/swisseph.js +1092 -0
- package/types/index.d.ts +255 -0
- package/wsam/swisseph.data +0 -0
- package/wsam/swisseph.js +3412 -0
- package/wsam/swisseph.wasm +0 -0
package/DOCUMENTATION.md
ADDED
|
@@ -0,0 +1,888 @@
|
|
|
1
|
+
# SwissEph WebAssembly Library Documentation
|
|
2
|
+
|
|
3
|
+
A JavaScript wrapper for the Swiss Ephemeris WebAssembly module, providing high-precision astronomical calculations for astrology, astronomy, and related applications.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [API Reference](#api-reference)
|
|
10
|
+
- [Examples](#examples)
|
|
11
|
+
- [Constants](#constants)
|
|
12
|
+
- [Advanced Usage](#advanced-usage)
|
|
13
|
+
- [Testing](#testing)
|
|
14
|
+
- [Browser Support](#browser-support)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Option 1: Direct Download
|
|
19
|
+
Download the library files and include them in your project:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
src/swisseph.js # Main library file
|
|
23
|
+
wsam/swisseph.js # WebAssembly module
|
|
24
|
+
wsam/swisseph.wasm # WebAssembly binary
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Option 2: ES Module Import
|
|
28
|
+
```javascript
|
|
29
|
+
import SwissEph from './src/swisseph.js';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Option 3: HTML Script Tag
|
|
33
|
+
```html
|
|
34
|
+
<script type="module">
|
|
35
|
+
import SwissEph from './src/swisseph.js';
|
|
36
|
+
// Your code here
|
|
37
|
+
</script>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
### Basic Setup
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
import SwissEph from './src/swisseph.js';
|
|
46
|
+
|
|
47
|
+
// Create instance
|
|
48
|
+
const swe = new SwissEph();
|
|
49
|
+
|
|
50
|
+
// Initialize the WebAssembly module
|
|
51
|
+
await swe.initSwissEph();
|
|
52
|
+
|
|
53
|
+
// Calculate Julian Day
|
|
54
|
+
const jd = swe.julday(2023, 6, 15, 12.0); // June 15, 2023, 12:00 UTC
|
|
55
|
+
|
|
56
|
+
// Calculate Sun position
|
|
57
|
+
const sunPosition = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
|
|
58
|
+
console.log(`Sun longitude: ${sunPosition[0]}°`);
|
|
59
|
+
|
|
60
|
+
// Clean up when done
|
|
61
|
+
swe.close();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Birth Chart Example
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
async function calculateBirthChart(year, month, day, hour, minute, timezone) {
|
|
68
|
+
const swe = new SwissEph();
|
|
69
|
+
await swe.initSwissEph();
|
|
70
|
+
|
|
71
|
+
// Convert local time to UTC
|
|
72
|
+
const utcHour = hour + minute / 60 - timezone;
|
|
73
|
+
const jd = swe.julday(year, month, day, utcHour);
|
|
74
|
+
|
|
75
|
+
// Define planets to calculate
|
|
76
|
+
const planets = [
|
|
77
|
+
{ id: swe.SE_SUN, name: 'Sun' },
|
|
78
|
+
{ id: swe.SE_MOON, name: 'Moon' },
|
|
79
|
+
{ id: swe.SE_MERCURY, name: 'Mercury' },
|
|
80
|
+
{ id: swe.SE_VENUS, name: 'Venus' },
|
|
81
|
+
{ id: swe.SE_MARS, name: 'Mars' },
|
|
82
|
+
{ id: swe.SE_JUPITER, name: 'Jupiter' },
|
|
83
|
+
{ id: swe.SE_SATURN, name: 'Saturn' },
|
|
84
|
+
{ id: swe.SE_URANUS, name: 'Uranus' },
|
|
85
|
+
{ id: swe.SE_NEPTUNE, name: 'Neptune' },
|
|
86
|
+
{ id: swe.SE_PLUTO, name: 'Pluto' }
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const chart = {};
|
|
90
|
+
|
|
91
|
+
for (const planet of planets) {
|
|
92
|
+
const result = swe.calc_ut(jd, planet.id, swe.SEFLG_SWIEPH);
|
|
93
|
+
chart[planet.name] = {
|
|
94
|
+
longitude: result[0],
|
|
95
|
+
latitude: result[1],
|
|
96
|
+
distance: result[2],
|
|
97
|
+
speed: result[3]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
swe.close();
|
|
102
|
+
return chart;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Usage
|
|
106
|
+
const chart = await calculateBirthChart(1990, 5, 15, 14, 30, -5); // May 15, 1990, 2:30 PM, UTC-5
|
|
107
|
+
console.log(chart);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## API Reference
|
|
111
|
+
|
|
112
|
+
### Core Methods
|
|
113
|
+
|
|
114
|
+
#### `initSwissEph()`
|
|
115
|
+
Initializes the WebAssembly module. Must be called before using any other methods.
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
await swe.initSwissEph();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### `julday(year, month, day, hour)`
|
|
122
|
+
Calculates Julian Day Number for a given date and time.
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const jd = swe.julday(2023, 6, 15, 12.5); // June 15, 2023, 12:30 UTC
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Parameters:**
|
|
129
|
+
- `year` (number): Year (e.g., 2023)
|
|
130
|
+
- `month` (number): Month (1-12)
|
|
131
|
+
- `day` (number): Day (1-31)
|
|
132
|
+
- `hour` (number): Hour in decimal format (0-24)
|
|
133
|
+
|
|
134
|
+
**Returns:** Julian Day Number (number)
|
|
135
|
+
|
|
136
|
+
#### `calc_ut(jd, planet, flags)`
|
|
137
|
+
Calculates planetary positions for Universal Time.
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
const result = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Parameters:**
|
|
144
|
+
- `jd` (number): Julian Day Number
|
|
145
|
+
- `planet` (number): Planet constant (e.g., `swe.SE_SUN`)
|
|
146
|
+
- `flags` (number): Calculation flags (e.g., `swe.SEFLG_SWIEPH`)
|
|
147
|
+
|
|
148
|
+
**Returns:** Float64Array with [longitude, latitude, distance, speed]
|
|
149
|
+
|
|
150
|
+
#### `calc(jd, planet, flags)`
|
|
151
|
+
Calculates planetary positions (alternative method with more detailed output).
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const result = swe.calc(jd, swe.SE_MOON, swe.SEFLG_SWIEPH);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Returns:** Object with detailed position data:
|
|
158
|
+
```javascript
|
|
159
|
+
{
|
|
160
|
+
longitude: number,
|
|
161
|
+
latitude: number,
|
|
162
|
+
distance: number,
|
|
163
|
+
longitudeSpeed: number,
|
|
164
|
+
latitudeSpeed: number,
|
|
165
|
+
distanceSpeed: number
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Time Functions
|
|
170
|
+
|
|
171
|
+
#### `deltat(jd)`
|
|
172
|
+
Calculates Delta T (difference between Terrestrial Time and Universal Time).
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
const deltaT = swe.deltat(jd);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### `sidtime(jd)`
|
|
179
|
+
Calculates sidereal time for a given Julian Day.
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
const siderealTime = swe.sidtime(jd);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `utc_to_jd(year, month, day, hour, minute, second, gregflag)`
|
|
186
|
+
Converts UTC time to Julian Day.
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
const result = swe.utc_to_jd(2023, 6, 15, 12, 30, 0, swe.SE_GREG_CAL);
|
|
190
|
+
// Returns: { julianDayET: number, julianDayUT: number }
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Date Conversion Functions
|
|
194
|
+
|
|
195
|
+
#### `revjul(jd, gregflag)`
|
|
196
|
+
Converts Julian Day back to calendar date.
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
const date = swe.revjul(jd, swe.SE_GREG_CAL);
|
|
200
|
+
// Returns: { year: number, month: number, day: number, hour: number }
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### `date_conversion(year, month, day, hour, gregflag)`
|
|
204
|
+
Converts calendar date to Julian Day.
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
const jd = swe.date_conversion(2023, 6, 15, 12.5, swe.SE_GREG_CAL);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Utility Functions
|
|
211
|
+
|
|
212
|
+
#### `degnorm(degrees)`
|
|
213
|
+
Normalizes degrees to 0-360 range.
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
const normalized = swe.degnorm(370); // Returns 10
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### `split_deg(degrees, roundflag)`
|
|
220
|
+
Splits decimal degrees into degrees, minutes, seconds.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
const split = swe.split_deg(123.456789, swe.SE_SPLIT_DEG_ROUND_SEC);
|
|
224
|
+
// Returns: { degree: 123, min: 27, second: 24, fraction: 0, sign: 4 }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### `day_of_week(jd)`
|
|
228
|
+
Returns day of week for a Julian Day (0=Monday, 6=Sunday).
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
const dayOfWeek = swe.day_of_week(jd);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Sidereal Functions
|
|
235
|
+
|
|
236
|
+
#### `set_sid_mode(sidmode, t0, ayan_t0)`
|
|
237
|
+
Sets sidereal calculation mode.
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
swe.set_sid_mode(swe.SE_SIDM_LAHIRI, 0, 0);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### `get_ayanamsa(jd)`
|
|
244
|
+
Gets ayanamsa value for sidereal calculations.
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
const ayanamsa = swe.get_ayanamsa(jd);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Information Functions
|
|
251
|
+
|
|
252
|
+
#### `version()`
|
|
253
|
+
Returns Swiss Ephemeris version string.
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
const version = swe.version();
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### `get_planet_name(planet)`
|
|
260
|
+
Returns planet name for a planet constant.
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
const name = swe.get_planet_name(swe.SE_SUN); // Returns "Sun"
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Cleanup
|
|
267
|
+
|
|
268
|
+
#### `close()`
|
|
269
|
+
Closes the Swiss Ephemeris and frees memory. Call when done.
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
swe.close();
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Examples
|
|
276
|
+
|
|
277
|
+
### Example 1: Current Planetary Positions
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
async function getCurrentPlanetaryPositions() {
|
|
281
|
+
const swe = new SwissEph();
|
|
282
|
+
await swe.initSwissEph();
|
|
283
|
+
|
|
284
|
+
const now = new Date();
|
|
285
|
+
const jd = swe.julday(
|
|
286
|
+
now.getUTCFullYear(),
|
|
287
|
+
now.getUTCMonth() + 1,
|
|
288
|
+
now.getUTCDate(),
|
|
289
|
+
now.getUTCHours() + now.getUTCMinutes() / 60
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const planets = [
|
|
293
|
+
swe.SE_SUN, swe.SE_MOON, swe.SE_MERCURY, swe.SE_VENUS,
|
|
294
|
+
swe.SE_MARS, swe.SE_JUPITER, swe.SE_SATURN
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
const positions = {};
|
|
298
|
+
|
|
299
|
+
for (const planet of planets) {
|
|
300
|
+
const result = swe.calc_ut(jd, planet, swe.SEFLG_SWIEPH);
|
|
301
|
+
const name = swe.get_planet_name(planet);
|
|
302
|
+
positions[name] = result[0]; // longitude in degrees
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
swe.close();
|
|
306
|
+
return positions;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Example 2: Sidereal vs Tropical Positions
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
async function compareSiderealTropical(year, month, day, hour) {
|
|
314
|
+
const swe = new SwissEph();
|
|
315
|
+
await swe.initSwissEph();
|
|
316
|
+
|
|
317
|
+
const jd = swe.julday(year, month, day, hour);
|
|
318
|
+
|
|
319
|
+
// Set Lahiri ayanamsa for sidereal calculations
|
|
320
|
+
swe.set_sid_mode(swe.SE_SIDM_LAHIRI, 0, 0);
|
|
321
|
+
|
|
322
|
+
// Tropical position
|
|
323
|
+
const tropical = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
|
|
324
|
+
|
|
325
|
+
// Sidereal position
|
|
326
|
+
const sidereal = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH | swe.SEFLG_SIDEREAL);
|
|
327
|
+
|
|
328
|
+
// Get ayanamsa value
|
|
329
|
+
const ayanamsa = swe.get_ayanamsa(jd);
|
|
330
|
+
|
|
331
|
+
swe.close();
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
tropical: tropical[0],
|
|
335
|
+
sidereal: sidereal[0],
|
|
336
|
+
ayanamsa: ayanamsa,
|
|
337
|
+
difference: tropical[0] - sidereal[0]
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Example 3: Time Zone Conversion
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
async function calculateWithTimeZone(year, month, day, hour, minute, second, timezone) {
|
|
346
|
+
const swe = new SwissEph();
|
|
347
|
+
await swe.initSwissEph();
|
|
348
|
+
|
|
349
|
+
// Convert to UTC using built-in function
|
|
350
|
+
const utcResult = swe.utc_to_jd(year, month, day, hour, minute, second, swe.SE_GREG_CAL);
|
|
351
|
+
|
|
352
|
+
// Adjust for timezone
|
|
353
|
+
const localJD = utcResult.julianDayUT - timezone / 24;
|
|
354
|
+
|
|
355
|
+
// Calculate planetary positions
|
|
356
|
+
const sunPos = swe.calc_ut(localJD, swe.SE_SUN, swe.SEFLG_SWIEPH);
|
|
357
|
+
|
|
358
|
+
swe.close();
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
julianDay: localJD,
|
|
362
|
+
sunLongitude: sunPos[0],
|
|
363
|
+
deltaT: swe.deltat(localJD)
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Example 4: Moon Phases
|
|
369
|
+
|
|
370
|
+
```javascript
|
|
371
|
+
async function getMoonPhase(year, month, day) {
|
|
372
|
+
const swe = new SwissEph();
|
|
373
|
+
await swe.initSwissEph();
|
|
374
|
+
|
|
375
|
+
const jd = swe.julday(year, month, day, 12.0);
|
|
376
|
+
|
|
377
|
+
// Get Sun and Moon positions
|
|
378
|
+
const sunPos = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
|
|
379
|
+
const moonPos = swe.calc_ut(jd, swe.SE_MOON, swe.SEFLG_SWIEPH);
|
|
380
|
+
|
|
381
|
+
// Calculate phase angle
|
|
382
|
+
let phaseAngle = moonPos[0] - sunPos[0];
|
|
383
|
+
if (phaseAngle < 0) phaseAngle += 360;
|
|
384
|
+
|
|
385
|
+
// Determine phase
|
|
386
|
+
let phase;
|
|
387
|
+
if (phaseAngle < 45 || phaseAngle > 315) phase = "New Moon";
|
|
388
|
+
else if (phaseAngle < 135) phase = "Waxing";
|
|
389
|
+
else if (phaseAngle < 225) phase = "Full Moon";
|
|
390
|
+
else phase = "Waning";
|
|
391
|
+
|
|
392
|
+
swe.close();
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
phaseAngle: phaseAngle,
|
|
396
|
+
phase: phase,
|
|
397
|
+
sunLongitude: sunPos[0],
|
|
398
|
+
moonLongitude: moonPos[0]
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Constants
|
|
404
|
+
|
|
405
|
+
### Planet Constants
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
// Major planets
|
|
409
|
+
swe.SE_SUN = 0;
|
|
410
|
+
swe.SE_MOON = 1;
|
|
411
|
+
swe.SE_MERCURY = 2;
|
|
412
|
+
swe.SE_VENUS = 3;
|
|
413
|
+
swe.SE_MARS = 4;
|
|
414
|
+
swe.SE_JUPITER = 5;
|
|
415
|
+
swe.SE_SATURN = 6;
|
|
416
|
+
swe.SE_URANUS = 7;
|
|
417
|
+
swe.SE_NEPTUNE = 8;
|
|
418
|
+
swe.SE_PLUTO = 9;
|
|
419
|
+
swe.SE_EARTH = 14;
|
|
420
|
+
|
|
421
|
+
// Lunar nodes and apogee
|
|
422
|
+
swe.SE_MEAN_NODE = 10;
|
|
423
|
+
swe.SE_TRUE_NODE = 11;
|
|
424
|
+
swe.SE_MEAN_APOG = 12;
|
|
425
|
+
swe.SE_OSCU_APOG = 13;
|
|
426
|
+
|
|
427
|
+
// Major asteroids
|
|
428
|
+
swe.SE_CHIRON = 15;
|
|
429
|
+
swe.SE_PHOLUS = 16;
|
|
430
|
+
swe.SE_CERES = 17;
|
|
431
|
+
swe.SE_PALLAS = 18;
|
|
432
|
+
swe.SE_JUNO = 19;
|
|
433
|
+
swe.SE_VESTA = 20;
|
|
434
|
+
|
|
435
|
+
// Uranian planets
|
|
436
|
+
swe.SE_CUPIDO = 40;
|
|
437
|
+
swe.SE_HADES = 41;
|
|
438
|
+
swe.SE_ZEUS = 42;
|
|
439
|
+
swe.SE_KRONOS = 43;
|
|
440
|
+
swe.SE_APOLLON = 44;
|
|
441
|
+
swe.SE_ADMETOS = 45;
|
|
442
|
+
swe.SE_VULKANUS = 46;
|
|
443
|
+
swe.SE_POSEIDON = 47;
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Calculation Flags
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
// Ephemeris types
|
|
450
|
+
swe.SEFLG_JPLEPH = 1; // JPL ephemeris
|
|
451
|
+
swe.SEFLG_SWIEPH = 2; // Swiss ephemeris (default)
|
|
452
|
+
swe.SEFLG_MOSEPH = 4; // Moshier ephemeris
|
|
453
|
+
|
|
454
|
+
// Coordinate systems
|
|
455
|
+
swe.SEFLG_HELCTR = 8; // Heliocentric
|
|
456
|
+
swe.SEFLG_BARYCTR = 16384; // Barycentric
|
|
457
|
+
swe.SEFLG_TOPOCTR = 32768; // Topocentric
|
|
458
|
+
swe.SEFLG_EQUATORIAL = 2048; // Equatorial coordinates
|
|
459
|
+
swe.SEFLG_XYZ = 4096; // Cartesian coordinates
|
|
460
|
+
swe.SEFLG_RADIANS = 8192; // Radians instead of degrees
|
|
461
|
+
|
|
462
|
+
// Special flags
|
|
463
|
+
swe.SEFLG_SPEED = 256; // Calculate speed
|
|
464
|
+
swe.SEFLG_TRUEPOS = 16; // True positions (no light-time correction)
|
|
465
|
+
swe.SEFLG_J2000 = 32; // J2000 coordinates
|
|
466
|
+
swe.SEFLG_NONUT = 64; // No nutation
|
|
467
|
+
swe.SEFLG_NOGDEFL = 512; // No gravitational deflection
|
|
468
|
+
swe.SEFLG_NOABERR = 1024; // No aberration
|
|
469
|
+
swe.SEFLG_SIDEREAL = 65536; // Sidereal positions
|
|
470
|
+
|
|
471
|
+
// Composite flags
|
|
472
|
+
swe.SEFLG_ASTROMETRIC = 1536; // No aberration + no gravitational deflection
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Sidereal Modes
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
swe.SE_SIDM_FAGAN_BRADLEY = 0;
|
|
479
|
+
swe.SE_SIDM_LAHIRI = 1;
|
|
480
|
+
swe.SE_SIDM_DELUCE = 2;
|
|
481
|
+
swe.SE_SIDM_RAMAN = 3;
|
|
482
|
+
swe.SE_SIDM_USHASHASHI = 4;
|
|
483
|
+
swe.SE_SIDM_KRISHNAMURTI = 5;
|
|
484
|
+
swe.SE_SIDM_DJWHAL_KHUL = 6;
|
|
485
|
+
swe.SE_SIDM_YUKTESHWAR = 7;
|
|
486
|
+
swe.SE_SIDM_JN_BHASIN = 8;
|
|
487
|
+
swe.SE_SIDM_BABYL_KUGLER1 = 9;
|
|
488
|
+
swe.SE_SIDM_BABYL_KUGLER2 = 10;
|
|
489
|
+
swe.SE_SIDM_BABYL_KUGLER3 = 11;
|
|
490
|
+
swe.SE_SIDM_BABYL_HUBER = 12;
|
|
491
|
+
swe.SE_SIDM_BABYL_ETPSC = 13;
|
|
492
|
+
swe.SE_SIDM_ALDEBARAN_15TAU = 14;
|
|
493
|
+
swe.SE_SIDM_HIPPARCHOS = 15;
|
|
494
|
+
swe.SE_SIDM_SASSANIAN = 16;
|
|
495
|
+
swe.SE_SIDM_GALCENT_0SAG = 17;
|
|
496
|
+
swe.SE_SIDM_J2000 = 18;
|
|
497
|
+
swe.SE_SIDM_J1900 = 19;
|
|
498
|
+
swe.SE_SIDM_B1950 = 20;
|
|
499
|
+
swe.SE_SIDM_USER = 255;
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### Calendar Types
|
|
503
|
+
|
|
504
|
+
```javascript
|
|
505
|
+
swe.SE_JUL_CAL = 0; // Julian calendar
|
|
506
|
+
swe.SE_GREG_CAL = 1; // Gregorian calendar
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Degree Splitting Flags
|
|
510
|
+
|
|
511
|
+
```javascript
|
|
512
|
+
swe.SE_SPLIT_DEG_ROUND_SEC = 1;
|
|
513
|
+
swe.SE_SPLIT_DEG_ROUND_MIN = 2;
|
|
514
|
+
swe.SE_SPLIT_DEG_ROUND_DEG = 4;
|
|
515
|
+
swe.SE_SPLIT_DEG_ZODIACAL = 8;
|
|
516
|
+
swe.SE_SPLIT_DEG_KEEP_SIGN = 16;
|
|
517
|
+
swe.SE_SPLIT_DEG_KEEP_DEG = 32;
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
## Advanced Usage
|
|
521
|
+
|
|
522
|
+
### Working with Fixed Stars
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
async function getFixedStarPosition(starName, year, month, day) {
|
|
526
|
+
const swe = new SwissEph();
|
|
527
|
+
await swe.initSwissEph();
|
|
528
|
+
|
|
529
|
+
const jd = swe.julday(year, month, day, 0);
|
|
530
|
+
|
|
531
|
+
// Calculate fixed star position
|
|
532
|
+
const starPos = swe.fixstar(starName, jd, swe.SEFLG_SWIEPH);
|
|
533
|
+
|
|
534
|
+
if (starPos) {
|
|
535
|
+
const result = {
|
|
536
|
+
name: starName,
|
|
537
|
+
longitude: starPos[0],
|
|
538
|
+
latitude: starPos[1],
|
|
539
|
+
distance: starPos[2],
|
|
540
|
+
magnitude: swe.fixstar_mag(starName)
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
swe.close();
|
|
544
|
+
return result;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
swe.close();
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Usage
|
|
552
|
+
const sirius = await getFixedStarPosition("Sirius", 2023, 6, 15);
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### House Calculations
|
|
556
|
+
|
|
557
|
+
```javascript
|
|
558
|
+
async function calculateHouses(year, month, day, hour, latitude, longitude, houseSystem = 'P') {
|
|
559
|
+
const swe = new SwissEph();
|
|
560
|
+
await swe.initSwissEph();
|
|
561
|
+
|
|
562
|
+
const jd = swe.julday(year, month, day, hour);
|
|
563
|
+
|
|
564
|
+
// Calculate houses
|
|
565
|
+
const houses = swe.houses(jd, latitude, longitude, houseSystem);
|
|
566
|
+
|
|
567
|
+
// Calculate house positions for planets
|
|
568
|
+
const planets = [swe.SE_SUN, swe.SE_MOON, swe.SE_MERCURY, swe.SE_VENUS, swe.SE_MARS];
|
|
569
|
+
const planetHouses = {};
|
|
570
|
+
|
|
571
|
+
for (const planet of planets) {
|
|
572
|
+
const planetPos = swe.calc_ut(jd, planet, swe.SEFLG_SWIEPH);
|
|
573
|
+
const housePos = swe.house_pos(
|
|
574
|
+
swe.sidtime(jd) * 15, // ARMC
|
|
575
|
+
latitude,
|
|
576
|
+
23.44, // obliquity
|
|
577
|
+
houseSystem,
|
|
578
|
+
planetPos[0],
|
|
579
|
+
planetPos[1]
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
planetHouses[swe.get_planet_name(planet)] = {
|
|
583
|
+
longitude: planetPos[0],
|
|
584
|
+
house: Math.floor(housePos)
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
swe.close();
|
|
589
|
+
|
|
590
|
+
return {
|
|
591
|
+
houses: houses,
|
|
592
|
+
planetHouses: planetHouses
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### Eclipse Calculations
|
|
598
|
+
|
|
599
|
+
```javascript
|
|
600
|
+
async function findNextSolarEclipse(startYear, startMonth, startDay) {
|
|
601
|
+
const swe = new SwissEph();
|
|
602
|
+
await swe.initSwissEph();
|
|
603
|
+
|
|
604
|
+
const startJD = swe.julday(startYear, startMonth, startDay, 12);
|
|
605
|
+
|
|
606
|
+
// Find next solar eclipse
|
|
607
|
+
const eclipse = swe.sol_eclipse_when_glob(
|
|
608
|
+
startJD,
|
|
609
|
+
swe.SEFLG_SWIEPH,
|
|
610
|
+
swe.SE_ECL_TOTAL | swe.SE_ECL_ANNULAR | swe.SE_ECL_PARTIAL,
|
|
611
|
+
0 // forward search
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
if (eclipse) {
|
|
615
|
+
const eclipseDate = swe.revjul(eclipse[1], swe.SE_GREG_CAL);
|
|
616
|
+
|
|
617
|
+
swe.close();
|
|
618
|
+
|
|
619
|
+
return {
|
|
620
|
+
julianDay: eclipse[1],
|
|
621
|
+
date: eclipseDate,
|
|
622
|
+
type: eclipse[0] & swe.SE_ECL_TOTAL ? 'Total' :
|
|
623
|
+
eclipse[0] & swe.SE_ECL_ANNULAR ? 'Annular' : 'Partial',
|
|
624
|
+
magnitude: eclipse[4]
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
swe.close();
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Topocentric Calculations
|
|
634
|
+
|
|
635
|
+
```javascript
|
|
636
|
+
async function calculateTopocentric(year, month, day, hour, latitude, longitude, altitude) {
|
|
637
|
+
const swe = new SwissEph();
|
|
638
|
+
await swe.initSwissEph();
|
|
639
|
+
|
|
640
|
+
// Set topocentric location
|
|
641
|
+
swe.set_topo(longitude, latitude, altitude);
|
|
642
|
+
|
|
643
|
+
const jd = swe.julday(year, month, day, hour);
|
|
644
|
+
|
|
645
|
+
// Calculate topocentric positions
|
|
646
|
+
const planets = [swe.SE_SUN, swe.SE_MOON, swe.SE_VENUS, swe.SE_MARS];
|
|
647
|
+
const positions = {};
|
|
648
|
+
|
|
649
|
+
for (const planet of planets) {
|
|
650
|
+
// Geocentric position
|
|
651
|
+
const geocentric = swe.calc_ut(jd, planet, swe.SEFLG_SWIEPH);
|
|
652
|
+
|
|
653
|
+
// Topocentric position
|
|
654
|
+
const topocentric = swe.calc_ut(jd, planet, swe.SEFLG_SWIEPH | swe.SEFLG_TOPOCTR);
|
|
655
|
+
|
|
656
|
+
positions[swe.get_planet_name(planet)] = {
|
|
657
|
+
geocentric: geocentric[0],
|
|
658
|
+
topocentric: topocentric[0],
|
|
659
|
+
difference: geocentric[0] - topocentric[0]
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
swe.close();
|
|
664
|
+
return positions;
|
|
665
|
+
}
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
## Error Handling
|
|
669
|
+
|
|
670
|
+
### Best Practices
|
|
671
|
+
|
|
672
|
+
```javascript
|
|
673
|
+
async function safeCalculation(year, month, day, hour) {
|
|
674
|
+
let swe = null;
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
swe = new SwissEph();
|
|
678
|
+
await swe.initSwissEph();
|
|
679
|
+
|
|
680
|
+
// Validate input
|
|
681
|
+
if (year < -5000 || year > 5000) {
|
|
682
|
+
throw new Error('Year out of valid range (-5000 to 5000)');
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if (month < 1 || month > 12) {
|
|
686
|
+
throw new Error('Month must be between 1 and 12');
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (day < 1 || day > 31) {
|
|
690
|
+
throw new Error('Day must be between 1 and 31');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (hour < 0 || hour >= 24) {
|
|
694
|
+
throw new Error('Hour must be between 0 and 23.999');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
const jd = swe.julday(year, month, day, hour);
|
|
698
|
+
|
|
699
|
+
// Check for valid Julian Day
|
|
700
|
+
if (isNaN(jd) || jd === swe.TJD_INVALID) {
|
|
701
|
+
throw new Error('Invalid Julian Day calculated');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const result = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
|
|
705
|
+
|
|
706
|
+
if (!result || result.length < 4) {
|
|
707
|
+
throw new Error('Failed to calculate planetary position');
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return {
|
|
711
|
+
success: true,
|
|
712
|
+
julianDay: jd,
|
|
713
|
+
longitude: result[0],
|
|
714
|
+
latitude: result[1],
|
|
715
|
+
distance: result[2],
|
|
716
|
+
speed: result[3]
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
} catch (error) {
|
|
720
|
+
return {
|
|
721
|
+
success: false,
|
|
722
|
+
error: error.message
|
|
723
|
+
};
|
|
724
|
+
} finally {
|
|
725
|
+
// Always clean up
|
|
726
|
+
if (swe) {
|
|
727
|
+
swe.close();
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
## Performance Tips
|
|
734
|
+
|
|
735
|
+
### 1. Reuse SwissEph Instance
|
|
736
|
+
|
|
737
|
+
```javascript
|
|
738
|
+
class AstrologyCalculator {
|
|
739
|
+
constructor() {
|
|
740
|
+
this.swe = null;
|
|
741
|
+
this.initialized = false;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
async init() {
|
|
745
|
+
if (!this.initialized) {
|
|
746
|
+
this.swe = new SwissEph();
|
|
747
|
+
await this.swe.initSwissEph();
|
|
748
|
+
this.initialized = true;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
async calculateChart(year, month, day, hour) {
|
|
753
|
+
await this.init();
|
|
754
|
+
|
|
755
|
+
const jd = this.swe.julday(year, month, day, hour);
|
|
756
|
+
const planets = [this.swe.SE_SUN, this.swe.SE_MOON, this.swe.SE_MERCURY];
|
|
757
|
+
const chart = {};
|
|
758
|
+
|
|
759
|
+
for (const planet of planets) {
|
|
760
|
+
const result = this.swe.calc_ut(jd, planet, this.swe.SEFLG_SWIEPH);
|
|
761
|
+
chart[this.swe.get_planet_name(planet)] = result[0];
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
return chart;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
destroy() {
|
|
768
|
+
if (this.swe) {
|
|
769
|
+
this.swe.close();
|
|
770
|
+
this.swe = null;
|
|
771
|
+
this.initialized = false;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Usage
|
|
777
|
+
const calculator = new AstrologyCalculator();
|
|
778
|
+
const chart1 = await calculator.calculateChart(1990, 5, 15, 14.5);
|
|
779
|
+
const chart2 = await calculator.calculateChart(1985, 12, 25, 8.0);
|
|
780
|
+
calculator.destroy(); // Clean up when done
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### 2. Batch Calculations
|
|
784
|
+
|
|
785
|
+
```javascript
|
|
786
|
+
async function batchCalculatePlanets(jd, planetList, flags) {
|
|
787
|
+
const swe = new SwissEph();
|
|
788
|
+
await swe.initSwissEph();
|
|
789
|
+
|
|
790
|
+
const results = {};
|
|
791
|
+
|
|
792
|
+
// Calculate all planets in one session
|
|
793
|
+
for (const planet of planetList) {
|
|
794
|
+
const result = swe.calc_ut(jd, planet, flags);
|
|
795
|
+
results[swe.get_planet_name(planet)] = result;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
swe.close();
|
|
799
|
+
return results;
|
|
800
|
+
}
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
## Browser Support
|
|
804
|
+
|
|
805
|
+
### Modern Browsers
|
|
806
|
+
- Chrome 61+
|
|
807
|
+
- Firefox 60+
|
|
808
|
+
- Safari 11+
|
|
809
|
+
- Edge 16+
|
|
810
|
+
|
|
811
|
+
### Requirements
|
|
812
|
+
- WebAssembly support
|
|
813
|
+
- ES6 modules support
|
|
814
|
+
- Async/await support
|
|
815
|
+
|
|
816
|
+
### Polyfills
|
|
817
|
+
For older browsers, you may need:
|
|
818
|
+
- WebAssembly polyfill
|
|
819
|
+
- ES6 module loader
|
|
820
|
+
- Promise polyfill
|
|
821
|
+
|
|
822
|
+
## Testing
|
|
823
|
+
|
|
824
|
+
The library includes comprehensive tests. To run them:
|
|
825
|
+
|
|
826
|
+
```bash
|
|
827
|
+
npm install
|
|
828
|
+
npm test
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
### Test Coverage
|
|
832
|
+
- 106 tests covering all major functionality
|
|
833
|
+
- 86.1% statement coverage
|
|
834
|
+
- Mock WebAssembly module for isolated testing
|
|
835
|
+
- Integration tests for real-world scenarios
|
|
836
|
+
|
|
837
|
+
## Troubleshooting
|
|
838
|
+
|
|
839
|
+
### Common Issues
|
|
840
|
+
|
|
841
|
+
1. **WebAssembly not loading**
|
|
842
|
+
```javascript
|
|
843
|
+
// Ensure proper path to WASM files
|
|
844
|
+
// Check browser console for loading errors
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
2. **Invalid Julian Day**
|
|
848
|
+
```javascript
|
|
849
|
+
// Validate date inputs before calculation
|
|
850
|
+
if (isNaN(jd) || jd === swe.TJD_INVALID) {
|
|
851
|
+
throw new Error('Invalid date');
|
|
852
|
+
}
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
3. **Memory leaks**
|
|
856
|
+
```javascript
|
|
857
|
+
// Always call close() when done
|
|
858
|
+
try {
|
|
859
|
+
// calculations
|
|
860
|
+
} finally {
|
|
861
|
+
swe.close();
|
|
862
|
+
}
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
4. **Incorrect time zones**
|
|
866
|
+
```javascript
|
|
867
|
+
// Convert to UTC before calculation
|
|
868
|
+
const utcHour = localHour - timezoneOffset;
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
## License
|
|
872
|
+
|
|
873
|
+
This library is a wrapper around the Swiss Ephemeris, which is licensed under the GNU General Public License (GPL) for non-commercial use. For commercial use, a license from Astrodienst is required.
|
|
874
|
+
|
|
875
|
+
## Support
|
|
876
|
+
|
|
877
|
+
For issues and questions:
|
|
878
|
+
- Check the test files for usage examples
|
|
879
|
+
- Review the Swiss Ephemeris documentation
|
|
880
|
+
- File issues on the project repository
|
|
881
|
+
|
|
882
|
+
## Version History
|
|
883
|
+
|
|
884
|
+
- v0.0.1: Initial release with core functionality
|
|
885
|
+
- Comprehensive test suite
|
|
886
|
+
- Full WebAssembly integration
|
|
887
|
+
- Modern ES6+ JavaScript API
|
|
888
|
+
```
|