@neaps/tide-predictor 0.0.5 → 0.1.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.
Files changed (52) hide show
  1. package/.eslintrc.cjs +18 -0
  2. package/.github/workflows/test.yml +8 -2
  3. package/.prettierrc +2 -1
  4. package/README.md +31 -15
  5. package/{lib/index.es6.js → dist/commonjs/index.js} +59 -59
  6. package/dist/commonjs/package.json +1 -0
  7. package/dist/{tide-predictor.js → web/tide-predictor.js} +58 -60
  8. package/dist/web/tide-predictor.min.js +1 -0
  9. package/package.json +24 -33
  10. package/rollup.config.js +2 -2
  11. package/src/astronomy/index.js +9 -9
  12. package/src/constituents/compound-constituent.js +3 -4
  13. package/src/constituents/constituent.js +5 -6
  14. package/src/constituents/index.js +17 -17
  15. package/src/harmonics/index.js +11 -11
  16. package/src/harmonics/prediction.js +12 -12
  17. package/src/index.js +3 -3
  18. package/src/node-corrections/index.js +2 -2
  19. package/{src/__mocks__ → test/_mocks}/constituents.js +0 -0
  20. package/{src/__mocks__ → test/_mocks}/secondary-station.js +0 -0
  21. package/{src/harmonics/__mocks__ → test/_mocks}/water-levels.js +0 -0
  22. package/test/astronomy/coefficients.js +15 -0
  23. package/test/astronomy/index.js +98 -0
  24. package/test/constituents/compound-constituent.js +46 -0
  25. package/test/constituents/constituent.js +67 -0
  26. package/test/constituents/index.js +35 -0
  27. package/{src/harmonics/__tests__ → test/harmonics}/index.js +29 -27
  28. package/{src/harmonics/__tests__ → test/harmonics}/prediction.js +37 -31
  29. package/{src/__tests__ → test}/index.js +23 -21
  30. package/test/lib/close-to.js +7 -0
  31. package/test/noaa.js +110 -0
  32. package/test/node-corrections/index.js +116 -0
  33. package/.eslintrc.js +0 -22
  34. package/Gruntfile.js +0 -87
  35. package/babel.config.js +0 -9
  36. package/lib/astronomy/coefficients.js +0 -31
  37. package/lib/astronomy/constants.js +0 -10
  38. package/lib/astronomy/index.js +0 -199
  39. package/lib/constituents/compound-constituent.js +0 -67
  40. package/lib/constituents/constituent.js +0 -74
  41. package/lib/constituents/index.js +0 -140
  42. package/lib/harmonics/index.js +0 -113
  43. package/lib/harmonics/prediction.js +0 -195
  44. package/lib/index.js +0 -53
  45. package/lib/node-corrections/index.js +0 -147
  46. package/src/__tests__/noaa.js +0 -92
  47. package/src/astronomy/__tests__/coefficients.js +0 -12
  48. package/src/astronomy/__tests__/index.js +0 -96
  49. package/src/constituents/__tests__/compound-constituent.js +0 -44
  50. package/src/constituents/__tests__/constituent.js +0 -65
  51. package/src/constituents/__tests__/index.js +0 -34
  52. package/src/node-corrections/__tests__/index.js +0 -114
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
3
  typeof define === 'function' && define.amd ? define(factory) :
4
- (global = global || self, global.tidePredictor = factory());
5
- }(this, function () { 'use strict';
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.tidePredictor = factory());
5
+ })(this, (function () { 'use strict';
6
6
 
7
7
  const d2r = Math.PI / 180.0;
8
8
  const r2d = 180.0 / Math.PI;
@@ -36,7 +36,7 @@
36
36
  sexagesimalToDecimal(0, 0, 7.12),
37
37
  sexagesimalToDecimal(0, 0, 27.87),
38
38
  sexagesimalToDecimal(0, 0, 5.79),
39
- sexagesimalToDecimal(0, 0, 2.45)
39
+ sexagesimalToDecimal(0, 0, 2.45),
40
40
  ].map((number, index) => {
41
41
  return number * Math.pow(1e-2, index)
42
42
  }),
@@ -45,7 +45,7 @@
45
45
  280.46645 - 357.5291,
46
46
  36000.76932 - 35999.0503,
47
47
  0.0003032 + 0.0001559,
48
- 0.00000048
48
+ 0.00000048,
49
49
  ],
50
50
 
51
51
  solarLongitude: [280.46645, 36000.76983, 0.0003032],
@@ -56,7 +56,7 @@
56
56
  218.3164591,
57
57
  481267.88134236,
58
58
  -0.0013268,
59
- 1 / 538841.0 - 1 / 65194000.0
59
+ 1 / 538841.0 - 1 / 65194000.0,
60
60
  ],
61
61
 
62
62
  lunarNode: [
@@ -64,7 +64,7 @@
64
64
  -1934.1361849,
65
65
  0.0020762,
66
66
  1 / 467410.0,
67
- -1 / 60616000.0
67
+ -1 / 60616000.0,
68
68
  ],
69
69
 
70
70
  lunarPerigee: [
@@ -72,8 +72,8 @@
72
72
  4069.0137111,
73
73
  -0.0103238,
74
74
  -1 / 80053.0,
75
- 1 / 18999000.0
76
- ]
75
+ 1 / 18999000.0,
76
+ ],
77
77
  };
78
78
 
79
79
  // Evaluates a polynomial at argument
@@ -99,12 +99,12 @@
99
99
  };
100
100
 
101
101
  // Meeus formula 11.1
102
- const T = t => {
102
+ const T = (t) => {
103
103
  return (JD(t) - 2451545.0) / 36525
104
104
  };
105
105
 
106
106
  // Meeus formula 7.1
107
- const JD = t => {
107
+ const JD = (t) => {
108
108
  let Y = t.getFullYear();
109
109
  let M = t.getMonth() + 1;
110
110
  const D =
@@ -200,11 +200,11 @@
200
200
  return r2d * 0.5 * Math.atan(tan2nupp)
201
201
  };
202
202
 
203
- const modulus = (a, b) => {
203
+ const modulus$1 = (a, b) => {
204
204
  return ((a % b) + b) % b
205
205
  };
206
206
 
207
- const astro = time => {
207
+ const astro = (time) => {
208
208
  const result = {};
209
209
  const polynomials = {
210
210
  s: coefficients.lunarLongitude,
@@ -220,9 +220,9 @@
220
220
  // Polynomials are in T, that is Julian Centuries; we want our speeds to be
221
221
  // in the more convenient unit of degrees per hour.
222
222
  const dTdHour = 1 / (24 * 365.25 * 100);
223
- Object.keys(polynomials).forEach(name => {
223
+ Object.keys(polynomials).forEach((name) => {
224
224
  result[name] = {
225
- value: modulus(polynomial(polynomials[name], T(time)), 360.0),
225
+ value: modulus$1(polynomial(polynomials[name], T(time)), 360.0),
226
226
  speed: derivativePolynomial(polynomials[name], T(time)) * dTdHour
227
227
  };
228
228
  });
@@ -237,10 +237,10 @@
237
237
  nup: _nup,
238
238
  nupp: _nupp
239
239
  };
240
- Object.keys(functions).forEach(name => {
240
+ Object.keys(functions).forEach((name) => {
241
241
  const functionCall = functions[name];
242
242
  result[name] = {
243
- value: modulus(
243
+ value: modulus$1(
244
244
  functionCall(result.N.value, result.i.value, result.omega.value),
245
245
  360.0
246
246
  ),
@@ -272,7 +272,7 @@
272
272
  return result
273
273
  };
274
274
 
275
- const modulus$1 = (a, b) => {
275
+ const modulus = (a, b) => {
276
276
  return ((a % b) + b) % b
277
277
  };
278
278
 
@@ -318,7 +318,7 @@
318
318
  const amplitudes = [];
319
319
  let result = 0;
320
320
 
321
- constituents.forEach(constituent => {
321
+ constituents.forEach((constituent) => {
322
322
  const amplitude = constituent.amplitude;
323
323
  const phase = constituent._phase;
324
324
  const f = modelF[constituent.name];
@@ -328,7 +328,7 @@
328
328
  amplitudes.push(amplitude * f * Math.cos(speed * hour + (V0 + u) - phase));
329
329
  });
330
330
  // sum up each row
331
- amplitudes.forEach(item => {
331
+ amplitudes.forEach((item) => {
332
332
  result += item;
333
333
  });
334
334
  return result
@@ -336,7 +336,7 @@
336
336
 
337
337
  const prediction = {};
338
338
 
339
- prediction.getExtremesPrediction = options => {
339
+ prediction.getExtremesPrediction = (options) => {
340
340
  const { labels, offsets } = typeof options !== 'undefined' ? options : {};
341
341
  const results = [];
342
342
  const { baseSpeed, u, f, baseValue } = prepare();
@@ -395,8 +395,8 @@
395
395
  timeline.items.forEach((time, index) => {
396
396
  const hour = timeline.hours[index];
397
397
  const prediction = {
398
- time: time,
399
- hour: hour,
398
+ time,
399
+ hour,
400
400
  level: getLevel(hour, baseSpeed, u[index], f[index], baseValue)
401
401
  };
402
402
 
@@ -412,31 +412,31 @@
412
412
  const baseSpeed = {};
413
413
  const u = [];
414
414
  const f = [];
415
- constituents.forEach(constituent => {
415
+ constituents.forEach((constituent) => {
416
416
  const value = constituent._model.value(baseAstro);
417
417
  const speed = constituent._model.speed(baseAstro);
418
418
  baseValue[constituent.name] = d2r * value;
419
419
  baseSpeed[constituent.name] = d2r * speed;
420
420
  });
421
- timeline.items.forEach(time => {
421
+ timeline.items.forEach((time) => {
422
422
  const uItem = {};
423
423
  const fItem = {};
424
424
  const itemAstro = astro(time);
425
- constituents.forEach(constituent => {
426
- const constituentU = modulus$1(constituent._model.u(itemAstro), 360);
425
+ constituents.forEach((constituent) => {
426
+ const constituentU = modulus(constituent._model.u(itemAstro), 360);
427
427
 
428
428
  uItem[constituent.name] = d2r * constituentU;
429
- fItem[constituent.name] = modulus$1(constituent._model.f(itemAstro), 360);
429
+ fItem[constituent.name] = modulus(constituent._model.f(itemAstro), 360);
430
430
  });
431
431
  u.push(uItem);
432
432
  f.push(fItem);
433
433
  });
434
434
 
435
435
  return {
436
- baseValue: baseValue,
437
- baseSpeed: baseSpeed,
438
- u: u,
439
- f: f
436
+ baseValue,
437
+ baseSpeed,
438
+ u,
439
+ f
440
440
  }
441
441
  };
442
442
 
@@ -588,7 +588,7 @@
588
588
 
589
589
  // Node factors u, see Table 2 of Schureman.
590
590
 
591
- uZero(a) {
591
+ uZero() {
592
592
  return 0.0
593
593
  },
594
594
 
@@ -663,7 +663,7 @@
663
663
  })
664
664
  };
665
665
 
666
- const astronimicDoodsonNumber = astro => {
666
+ const astronimicDoodsonNumber = (astro) => {
667
667
  return [
668
668
  astro['T+h-s'],
669
669
  astro.s,
@@ -675,17 +675,17 @@
675
675
  ]
676
676
  };
677
677
 
678
- const astronomicSpeed = astro => {
678
+ const astronomicSpeed = (astro) => {
679
679
  const results = [];
680
- astronimicDoodsonNumber(astro).forEach(number => {
680
+ astronimicDoodsonNumber(astro).forEach((number) => {
681
681
  results.push(number.speed);
682
682
  });
683
683
  return results
684
684
  };
685
685
 
686
- const astronomicValues = astro => {
686
+ const astronomicValues = (astro) => {
687
687
  const results = [];
688
- astronimicDoodsonNumber(astro).forEach(number => {
688
+ astronimicDoodsonNumber(astro).forEach((number) => {
689
689
  results.push(number.value);
690
690
  });
691
691
  return results
@@ -697,11 +697,10 @@
697
697
  }
698
698
 
699
699
  const constituent = {
700
- name: name,
700
+ name,
701
+ coefficients,
701
702
 
702
- coefficients: coefficients,
703
-
704
- value: astro => {
703
+ value: (astro) => {
705
704
  return dotArray(coefficients, astronomicValues(astro))
706
705
  },
707
706
 
@@ -729,11 +728,10 @@
729
728
  });
730
729
 
731
730
  const compoundConstituent = {
732
- name: name,
733
-
734
- coefficients: coefficients,
731
+ name,
732
+ coefficients,
735
733
 
736
- speed: astro => {
734
+ speed: (astro) => {
737
735
  let speed = 0;
738
736
  members.forEach(({ constituent, factor }) => {
739
737
  speed += constituent.speed(astro) * factor;
@@ -741,7 +739,7 @@
741
739
  return speed
742
740
  },
743
741
 
744
- value: astro => {
742
+ value: (astro) => {
745
743
  let value = 0;
746
744
  members.forEach(({ constituent, factor }) => {
747
745
  value += constituent.value(astro) * factor;
@@ -749,7 +747,7 @@
749
747
  return value
750
748
  },
751
749
 
752
- u: astro => {
750
+ u: (astro) => {
753
751
  let u = 0;
754
752
  members.forEach(({ constituent, factor }) => {
755
753
  u += constituent.u(astro) * factor;
@@ -757,7 +755,7 @@
757
755
  return u
758
756
  },
759
757
 
760
- f: astro => {
758
+ f: (astro) => {
761
759
  const f = [];
762
760
  members.forEach(({ constituent, factor }) => {
763
761
  f.push(Math.pow(constituent.f(astro), Math.abs(factor)));
@@ -812,10 +810,10 @@
812
810
  constituents.M3 = constituentFactory(
813
811
  'M3',
814
812
  [3, 0, 0, 0, 0, 0, 0],
815
- a => {
813
+ (a) => {
816
814
  return corrections.uModd(a, 3)
817
815
  },
818
- a => {
816
+ (a) => {
819
817
  return corrections.fModd(a, 3)
820
818
  }
821
819
  );
@@ -885,7 +883,7 @@
885
883
  { constituent: constituents.M2, factor: 4 }
886
884
  ]);
887
885
 
888
- const getDate = time => {
886
+ const getDate = (time) => {
889
887
  if (time instanceof Date) {
890
888
  return time
891
889
  }
@@ -897,20 +895,20 @@
897
895
 
898
896
  const getTimeline = (start, end, seconds) => {
899
897
  seconds = typeof seconds !== 'undefined' ? seconds : 10 * 60;
900
- const timeline = [];
898
+ const items = [];
901
899
  const endTime = end.getTime() / 1000;
902
900
  let lastTime = start.getTime() / 1000;
903
901
  const startTime = lastTime;
904
902
  const hours = [];
905
903
  while (lastTime <= endTime) {
906
- timeline.push(new Date(lastTime * 1000));
904
+ items.push(new Date(lastTime * 1000));
907
905
  hours.push((lastTime - startTime) / (60 * 60));
908
906
  lastTime += seconds;
909
907
  }
910
908
 
911
909
  return {
912
- items: timeline,
913
- hours: hours
910
+ items,
911
+ hours
914
912
  }
915
913
  };
916
914
 
@@ -919,7 +917,7 @@
919
917
  throw new Error('Harmonic constituents are not an array')
920
918
  }
921
919
  const constituents$1 = [];
922
- harmonicConstituents.forEach((constituent, index) => {
920
+ harmonicConstituents.forEach((constituent) => {
923
921
  if (typeof constituent.name === 'undefined') {
924
922
  throw new Error('Harmonic constituents must have a name property')
925
923
  }
@@ -953,13 +951,13 @@
953
951
  return harmonics
954
952
  };
955
953
 
956
- harmonics.prediction = options => {
954
+ harmonics.prediction = (options) => {
957
955
  options =
958
956
  typeof options !== 'undefined' ? options : { timeFidelity: 10 * 60 };
959
957
  return predictionFactory({
960
958
  timeline: getTimeline(start, end, options.timeFidelity),
961
959
  constituents: constituents$1,
962
- start: start
960
+ start
963
961
  })
964
962
  };
965
963
 
@@ -974,7 +972,7 @@
974
972
  };
975
973
 
976
974
  if (typeof options !== 'undefined') {
977
- Object.keys(harmonicsOptions).forEach(key => {
975
+ Object.keys(harmonicsOptions).forEach((key) => {
978
976
  if (typeof options[key] !== 'undefined') {
979
977
  harmonicsOptions[key] = options[key];
980
978
  }
@@ -992,7 +990,7 @@
992
990
  getExtremesPrediction: ({ start, end, labels, offsets, timeFidelity }) => {
993
991
  return harmonicsFactory(harmonicsOptions)
994
992
  .setTimeSpan(start, end)
995
- .prediction({ timeFidelity: timeFidelity })
993
+ .prediction({ timeFidelity })
996
994
  .getExtremesPrediction(labels, offsets)
997
995
  },
998
996
 
@@ -0,0 +1 @@
1
+ (function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,global.tidePredictor=factory())})(this,function(){"use strict";const d2r=Math.PI/180;const r2d=180/Math.PI;const sexagesimalToDecimal=(degrees,arcmins,arcsecs,mas,muas)=>{arcmins=typeof arcmins!=="undefined"?arcmins:0;arcsecs=typeof arcsecs!=="undefined"?arcsecs:0;mas=typeof mas!=="undefined"?mas:0;muas=typeof muas!=="undefined"?muas:0;return degrees+arcmins/60+arcsecs/(60*60)+mas/(60*60*1e3)+muas/(60*60*1e6)};const coefficients={terrestrialObliquity:[sexagesimalToDecimal(23,26,21.448),-sexagesimalToDecimal(0,0,4680.93),-sexagesimalToDecimal(0,0,1.55),sexagesimalToDecimal(0,0,1999.25),-sexagesimalToDecimal(0,0,51.38),-sexagesimalToDecimal(0,0,249.67),-sexagesimalToDecimal(0,0,39.05),sexagesimalToDecimal(0,0,7.12),sexagesimalToDecimal(0,0,27.87),sexagesimalToDecimal(0,0,5.79),sexagesimalToDecimal(0,0,2.45)].map((number,index)=>{return number*Math.pow(.01,index)}),solarPerigee:[280.46645-357.5291,36000.76932-35999.0503,3032e-7+1559e-7,48e-8],solarLongitude:[280.46645,36000.76983,3032e-7],lunarInclination:[5.145],lunarLongitude:[218.3164591,481267.88134236,-.0013268,1/538841-1/65194e3],lunarNode:[125.044555,-1934.1361849,.0020762,1/467410,-1/60616e3],lunarPerigee:[83.353243,4069.0137111,-.0103238,-1/80053,1/18999e3]};const polynomial=(coefficients,argument)=>{const result=[];coefficients.forEach((coefficient,index)=>{result.push(coefficient*Math.pow(argument,index))});return result.reduce((a,b)=>{return a+b})};const derivativePolynomial=(coefficients,argument)=>{const result=[];coefficients.forEach((coefficient,index)=>{result.push(coefficient*index*Math.pow(argument,index-1))});return result.reduce((a,b)=>{return a+b})};const T=t=>{return(JD(t)-2451545)/36525};const JD=t=>{let Y=t.getFullYear();let M=t.getMonth()+1;const D=t.getDate()+t.getHours()/24+t.getMinutes()/(24*60)+t.getSeconds()/(24*60*60)+t.getMilliseconds()/(24*60*60*1e6);if(M<=2){Y=Y-1;M=M+12}const A=Math.floor(Y/100);const B=2-A+Math.floor(A/4);return Math.floor(365.25*(Y+4716))+Math.floor(30.6001*(M+1))+D+B-1524.5};const _I=(N,i,omega)=>{N=d2r*N;i=d2r*i;omega=d2r*omega;const cosI=Math.cos(i)*Math.cos(omega)-Math.sin(i)*Math.sin(omega)*Math.cos(N);return r2d*Math.acos(cosI)};const _xi=(N,i,omega)=>{N=d2r*N;i=d2r*i;omega=d2r*omega;let e1=Math.cos(.5*(omega-i))/Math.cos(.5*(omega+i))*Math.tan(.5*N);let e2=Math.sin(.5*(omega-i))/Math.sin(.5*(omega+i))*Math.tan(.5*N);e1=Math.atan(e1);e2=Math.atan(e2);e1=e1-.5*N;e2=e2-.5*N;return-(e1+e2)*r2d};const _nu=(N,i,omega)=>{N=d2r*N;i=d2r*i;omega=d2r*omega;let e1=Math.cos(.5*(omega-i))/Math.cos(.5*(omega+i))*Math.tan(.5*N);let e2=Math.sin(.5*(omega-i))/Math.sin(.5*(omega+i))*Math.tan(.5*N);e1=Math.atan(e1);e2=Math.atan(e2);e1=e1-.5*N;e2=e2-.5*N;return(e1-e2)*r2d};const _nup=(N,i,omega)=>{const I=d2r*_I(N,i,omega);const nu=d2r*_nu(N,i,omega);return r2d*Math.atan(Math.sin(2*I)*Math.sin(nu)/(Math.sin(2*I)*Math.cos(nu)+.3347))};const _nupp=(N,i,omega)=>{const I=d2r*_I(N,i,omega);const nu=d2r*_nu(N,i,omega);const tan2nupp=Math.sin(I)**2*Math.sin(2*nu)/(Math.sin(I)**2*Math.cos(2*nu)+.0727);return r2d*.5*Math.atan(tan2nupp)};const modulus$1=(a,b)=>{return(a%b+b)%b};const astro=time=>{const result={};const polynomials={s:coefficients.lunarLongitude,h:coefficients.solarLongitude,p:coefficients.lunarPerigee,N:coefficients.lunarNode,pp:coefficients.solarPerigee,90:[90],omega:coefficients.terrestrialObliquity,i:coefficients.lunarInclination};const dTdHour=1/(24*365.25*100);Object.keys(polynomials).forEach(name=>{result[name]={value:modulus$1(polynomial(polynomials[name],T(time)),360),speed:derivativePolynomial(polynomials[name],T(time))*dTdHour}});const functions={I:_I,xi:_xi,nu:_nu,nup:_nup,nupp:_nupp};Object.keys(functions).forEach(name=>{const functionCall=functions[name];result[name]={value:modulus$1(functionCall(result.N.value,result.i.value,result.omega.value),360),speed:null}});const hour={value:(JD(time)-Math.floor(JD(time)))*360,speed:15};result["T+h-s"]={value:hour.value+result.h.value-result.s.value,speed:hour.speed+result.h.speed-result.s.speed};result.P={value:result.p.value-result.xi.value%360,speed:null};return result};const modulus=(a,b)=>{return(a%b+b)%b};const addExtremesOffsets=(extreme,offsets)=>{if(typeof offsets==="undefined"||!offsets){return extreme}if(extreme.high&&offsets.height_offset&&offsets.height_offset.high){extreme.level*=offsets.height_offset.high}if(extreme.low&&offsets.height_offset&&offsets.height_offset.low){extreme.level*=offsets.height_offset.low}if(extreme.high&&offsets.time_offset&&offsets.time_offset.high){extreme.time=new Date(extreme.time.getTime()+offsets.time_offset.high*60*1e3)}if(extreme.low&&offsets.time_offset&&offsets.time_offset.low){extreme.time=new Date(extreme.time.getTime()+offsets.time_offset.low*60*1e3)}return extreme};const getExtremeLabel=(label,highLowLabels)=>{if(typeof highLowLabels!=="undefined"&&typeof highLowLabels[label]!=="undefined"){return highLowLabels[label]}const labels={high:"High",low:"Low"};return labels[label]};const predictionFactory=({timeline,constituents,start})=>{const getLevel=(hour,modelBaseSpeed,modelU,modelF,modelBaseValue)=>{const amplitudes=[];let result=0;constituents.forEach(constituent=>{const amplitude=constituent.amplitude;const phase=constituent._phase;const f=modelF[constituent.name];const speed=modelBaseSpeed[constituent.name];const u=modelU[constituent.name];const V0=modelBaseValue[constituent.name];amplitudes.push(amplitude*f*Math.cos(speed*hour+(V0+u)-phase))});amplitudes.forEach(item=>{result+=item});return result};const prediction={};prediction.getExtremesPrediction=options=>{const{labels,offsets}=typeof options!=="undefined"?options:{};const results=[];const{baseSpeed,u,f,baseValue}=prepare();let goingUp=false;let goingDown=false;let lastLevel=getLevel(0,baseSpeed,u[0],f[0],baseValue);timeline.items.forEach((time,index)=>{const hour=timeline.hours[index];const level=getLevel(hour,baseSpeed,u[index],f[index],baseValue);if(level>lastLevel&&goingDown){results.push(addExtremesOffsets({time:timeline.items[index-1],level:lastLevel,high:false,low:true,label:getExtremeLabel("low",labels)},offsets))}if(level<lastLevel&&goingUp){results.push(addExtremesOffsets({time:timeline.items[index-1],level:lastLevel,high:true,low:false,label:getExtremeLabel("high",labels)},offsets))}if(level>lastLevel){goingUp=true;goingDown=false}if(level<lastLevel){goingUp=false;goingDown=true}lastLevel=level});return results};prediction.getTimelinePrediction=()=>{const results=[];const{baseSpeed,u,f,baseValue}=prepare();timeline.items.forEach((time,index)=>{const hour=timeline.hours[index];const prediction={time:time,hour:hour,level:getLevel(hour,baseSpeed,u[index],f[index],baseValue)};results.push(prediction)});return results};const prepare=()=>{const baseAstro=astro(start);const baseValue={};const baseSpeed={};const u=[];const f=[];constituents.forEach(constituent=>{const value=constituent._model.value(baseAstro);const speed=constituent._model.speed(baseAstro);baseValue[constituent.name]=d2r*value;baseSpeed[constituent.name]=d2r*speed});timeline.items.forEach(time=>{const uItem={};const fItem={};const itemAstro=astro(time);constituents.forEach(constituent=>{const constituentU=modulus(constituent._model.u(itemAstro),360);uItem[constituent.name]=d2r*constituentU;fItem[constituent.name]=modulus(constituent._model.f(itemAstro),360)});u.push(uItem);f.push(fItem)});return{baseValue:baseValue,baseSpeed:baseSpeed,u:u,f:f}};return Object.freeze(prediction)};const corrections={fUnity(){return 1},fMm(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const mean=(2/3-Math.pow(Math.sin(omega),2))*(1-3/2*Math.pow(Math.sin(i),2));return(2/3-Math.pow(Math.sin(I),2))/mean},fMf(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const mean=Math.pow(Math.sin(omega),2)*Math.pow(Math.cos(.5*i),4);return Math.pow(Math.sin(I),2)/mean},fO1(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const mean=Math.sin(omega)*Math.pow(Math.cos(.5*omega),2)*Math.pow(Math.cos(.5*i),4);return Math.sin(I)*Math.pow(Math.cos(.5*I),2)/mean},fJ1(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const mean=Math.sin(2*omega)*(1-3/2*Math.pow(Math.sin(i),2));return Math.sin(2*I)/mean},fOO1(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const mean=Math.sin(omega)*Math.pow(Math.sin(.5*omega),2)*Math.pow(Math.cos(.5*i),4);return Math.sin(I)*Math.pow(Math.sin(.5*I),2)/mean},fM2(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const mean=Math.pow(Math.cos(.5*omega),4)*Math.pow(Math.cos(.5*i),4);return Math.pow(Math.cos(.5*I),4)/mean},fK1(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const nu=d2r*a.nu.value;const sin2IcosnuMean=Math.sin(2*omega)*(1-3/2*Math.pow(Math.sin(i),2));const mean=.5023*sin2IcosnuMean+.1681;return Math.pow(.2523*Math.pow(Math.sin(2*I),2)+.1689*Math.sin(2*I)*Math.cos(nu)+.0283,.5)/mean},fL2(a){const P=d2r*a.P.value;const I=d2r*a.I.value;const rAInv=Math.pow(1-12*Math.pow(Math.tan(.5*I),2)*Math.cos(2*P)+36*Math.pow(Math.tan(.5*I),4),.5);return corrections.fM2(a)*rAInv},fK2(a){const omega=d2r*a.omega.value;const i=d2r*a.i.value;const I=d2r*a.I.value;const nu=d2r*a.nu.value;const sinsqIcos2nuMean=Math.sin(omega)**2*(1-3/2*Math.sin(i)**2);const mean=.5023*sinsqIcos2nuMean+.0365;return Math.pow(.2523*Math.pow(Math.sin(I),4)+.0367*Math.pow(Math.sin(I),2)*Math.cos(2*nu)+.0013,.5)/mean},fM1(a){const P=d2r*a.P.value;const I=d2r*a.I.value;const qAInv=Math.pow(.25+1.5*Math.cos(I)*Math.cos(2*P)*Math.pow(Math.cos(.5*I),-.5)+2.25*Math.pow(Math.cos(I),2)*Math.pow(Math.cos(.5*I),-4),.5);return corrections.fO1(a)*qAInv},fModd(a,n){return Math.pow(corrections.fM2(a),n/2)},uZero(){return 0},uMf(a){return-2*a.xi.value},uO1(a){return 2*a.xi.value-a.nu.value},uJ1(a){return-a.nu.value},uOO1(a){return-2*a.xi.value-a.nu.value},uM2(a){return 2*a.xi.value-2*a.nu.value},uK1(a){return-a.nup.value},uL2(a){const I=d2r*a.I.value;const P=d2r*a.P.value;const R=r2d*Math.atan(Math.sin(2*P)/(1/6*Math.pow(Math.tan(.5*I),-2)-Math.cos(2*P)));return 2*a.xi.value-2*a.nu.value-R},uK2(a){return-2*a.nupp.value},uM1(a){const I=d2r*a.I.value;const P=d2r*a.P.value;const Q=r2d*Math.atan((5*Math.cos(I)-1)/(7*Math.cos(I)+1)*Math.tan(P));return a.xi.value-a.nu.value+Q},uModd(a,n){return n/2*corrections.uM2(a)}};const dotArray=(a,b)=>{const results=[];a.forEach((value,index)=>{results.push(value*b[index])});return results.reduce((total,value)=>{return total+value})};const astronimicDoodsonNumber=astro=>{return[astro["T+h-s"],astro.s,astro.h,astro.p,astro.N,astro.pp,astro["90"]]};const astronomicSpeed=astro=>{const results=[];astronimicDoodsonNumber(astro).forEach(number=>{results.push(number.speed)});return results};const astronomicValues=astro=>{const results=[];astronimicDoodsonNumber(astro).forEach(number=>{results.push(number.value)});return results};const constituentFactory=(name,coefficients,u,f)=>{if(!coefficients){throw new Error("Coefficient must be defined for a constituent")}const constituent={name:name,coefficients:coefficients,value:astro=>{return dotArray(coefficients,astronomicValues(astro))},speed(astro){return dotArray(coefficients,astronomicSpeed(astro))},u:typeof u!=="undefined"?u:corrections.uZero,f:typeof f!=="undefined"?f:corrections.fUnity};return Object.freeze(constituent)};const compoundConstituentFactory=(name,members)=>{const coefficients=[];members.forEach(({constituent,factor})=>{constituent.coefficients.forEach((coefficient,index)=>{if(typeof coefficients[index]==="undefined"){coefficients[index]=0}coefficients[index]+=coefficient*factor})});const compoundConstituent={name:name,coefficients:coefficients,speed:astro=>{let speed=0;members.forEach(({constituent,factor})=>{speed+=constituent.speed(astro)*factor});return speed},value:astro=>{let value=0;members.forEach(({constituent,factor})=>{value+=constituent.value(astro)*factor});return value},u:astro=>{let u=0;members.forEach(({constituent,factor})=>{u+=constituent.u(astro)*factor});return u},f:astro=>{const f=[];members.forEach(({constituent,factor})=>{f.push(Math.pow(constituent.f(astro),Math.abs(factor)))});return f.reduce((previous,value)=>{return previous*value})}};return Object.freeze(compoundConstituent)};const constituents={};constituents.Z0=constituentFactory("Z0",[0,0,0,0,0,0,0],corrections.uZero,corrections.fUnity);constituents.SA=constituentFactory("Sa",[0,0,1,0,0,0,0],corrections.uZero,corrections.fUnity);constituents.SSA=constituentFactory("Ssa",[0,0,2,0,0,0,0],corrections.uZero,corrections.fUnity);constituents.MM=constituentFactory("MM",[0,1,0,-1,0,0,0],corrections.uZero,corrections.fMm);constituents.MF=constituentFactory("MF",[0,2,0,0,0,0,0],corrections.uMf,corrections.fMf);constituents.Q1=constituentFactory("Q1",[1,-2,0,1,0,0,1],corrections.uO1,corrections.fO1);constituents.O1=constituentFactory("O1",[1,-1,0,0,0,0,1],corrections.uO1,corrections.fO1);constituents.K1=constituentFactory("K1",[1,1,0,0,0,0,-1],corrections.uK1,corrections.fK1);constituents.J1=constituentFactory("J1",[1,2,0,-1,0,0,-1],corrections.uJ1,corrections.fJ1);constituents.M1=constituentFactory("M1",[1,0,0,0,0,0,1],corrections.uM1,corrections.fM1);constituents.P1=constituentFactory("P1",[1,1,-2,0,0,0,1],corrections.uZero,corrections.fUnity);constituents.S1=constituentFactory("S1",[1,1,-1,0,0,0,0],corrections.uZero,corrections.fUnity);constituents.OO1=constituentFactory("OO1",[1,3,0,0,0,0,-1],corrections.uOO1,corrections.fOO1);constituents["2N2"]=constituentFactory("2N2",[2,-2,0,2,0,0,0],corrections.uM2,corrections.fM2);constituents.N2=constituentFactory("N2",[2,-1,0,1,0,0,0],corrections.uM2,corrections.fM2);constituents.NU2=constituentFactory("NU2",[2,-1,2,-1,0,0,0],corrections.uM2,corrections.fM2);constituents.M2=constituentFactory("M2",[2,0,0,0,0,0,0],corrections.uM2,corrections.fM2);constituents.LAM2=constituentFactory("LAM2",[2,1,-2,1,0,0,2],corrections.uM2,corrections.fM2);constituents.L2=constituentFactory("L2",[2,1,0,-1,0,0,2],corrections.uL2,corrections.fL2);constituents.T2=constituentFactory("T2",[2,2,-3,0,0,1,0],corrections.uZero,corrections.fUnity);constituents.S2=constituentFactory("S2",[2,2,-2,0,0,0,0],corrections.uZero,corrections.fUnity);constituents.R2=constituentFactory("R2",[2,2,-1,0,0,-1,2],corrections.uZero,corrections.fUnity);constituents.K2=constituentFactory("K2",[2,2,0,0,0,0,0],corrections.uK2,corrections.fK2);constituents.M3=constituentFactory("M3",[3,0,0,0,0,0,0],a=>{return corrections.uModd(a,3)},a=>{return corrections.fModd(a,3)});constituents.MSF=compoundConstituentFactory("MSF",[{constituent:constituents.S2,factor:1},{constituent:constituents.M2,factor:-1}]);constituents["2Q1"]=compoundConstituentFactory("2Q1",[{constituent:constituents.N2,factor:1},{constituent:constituents.J1,factor:-1}]);constituents.RHO=compoundConstituentFactory("RHO",[{constituent:constituents.NU2,factor:1},{constituent:constituents.K1,factor:-1}]);constituents.MU2=compoundConstituentFactory("MU2",[{constituent:constituents.M2,factor:2},{constituent:constituents.S2,factor:-1}]);constituents["2SM2"]=compoundConstituentFactory("2SM2",[{constituent:constituents.S2,factor:2},{constituent:constituents.M2,factor:-1}]);constituents["2MK3"]=compoundConstituentFactory("2MK3",[{constituent:constituents.M2,factor:1},{constituent:constituents.O1,factor:1}]);constituents.MK3=compoundConstituentFactory("MK3",[{constituent:constituents.M2,factor:1},{constituent:constituents.K1,factor:1}]);constituents.MN4=compoundConstituentFactory("MN4",[{constituent:constituents.M2,factor:1},{constituent:constituents.N2,factor:1}]);constituents.M4=compoundConstituentFactory("M4",[{constituent:constituents.M2,factor:2}]);constituents.MS4=compoundConstituentFactory("MS4",[{constituent:constituents.M2,factor:1},{constituent:constituents.S2,factor:1}]);constituents.S4=compoundConstituentFactory("S4",[{constituent:constituents.S2,factor:2}]);constituents.M6=compoundConstituentFactory("M6",[{constituent:constituents.M2,factor:3}]);constituents.S6=compoundConstituentFactory("S6",[{constituent:constituents.S2,factor:3}]);constituents.M8=compoundConstituentFactory("M8",[{constituent:constituents.M2,factor:4}]);const getDate=time=>{if(time instanceof Date){return time}if(typeof time==="number"){return new Date(time*1e3)}throw new Error("Invalid date format, should be a Date object, or timestamp")};const getTimeline=(start,end,seconds)=>{seconds=typeof seconds!=="undefined"?seconds:10*60;const items=[];const endTime=end.getTime()/1e3;let lastTime=start.getTime()/1e3;const startTime=lastTime;const hours=[];while(lastTime<=endTime){items.push(new Date(lastTime*1e3));hours.push((lastTime-startTime)/(60*60));lastTime+=seconds}return{items:items,hours:hours}};const harmonicsFactory=({harmonicConstituents,phaseKey,offset})=>{if(!Array.isArray(harmonicConstituents)){throw new Error("Harmonic constituents are not an array")}const constituents$1=[];harmonicConstituents.forEach(constituent=>{if(typeof constituent.name==="undefined"){throw new Error("Harmonic constituents must have a name property")}if(typeof constituents[constituent.name]!=="undefined"){constituent._model=constituents[constituent.name];constituent._phase=d2r*constituent[phaseKey];constituents$1.push(constituent)}});if(offset!==false){constituents$1.push({name:"Z0",_model:constituents.Z0,_phase:0,amplitude:offset})}let start=new Date;let end=new Date;const harmonics={};harmonics.setTimeSpan=(startTime,endTime)=>{start=getDate(startTime);end=getDate(endTime);if(start.getTime()>=end.getTime()){throw new Error("Start time must be before end time")}return harmonics};harmonics.prediction=options=>{options=typeof options!=="undefined"?options:{timeFidelity:10*60};return predictionFactory({timeline:getTimeline(start,end,options.timeFidelity),constituents:constituents$1,start:start})};return Object.freeze(harmonics)};const tidePredictionFactory=(constituents,options)=>{const harmonicsOptions={harmonicConstituents:constituents,phaseKey:"phase_GMT",offset:false};if(typeof options!=="undefined"){Object.keys(harmonicsOptions).forEach(key=>{if(typeof options[key]!=="undefined"){harmonicsOptions[key]=options[key]}})}const tidePrediction={getTimelinePrediction:({start,end})=>{return harmonicsFactory(harmonicsOptions).setTimeSpan(start,end).prediction().getTimelinePrediction()},getExtremesPrediction:({start,end,labels,offsets,timeFidelity})=>{return harmonicsFactory(harmonicsOptions).setTimeSpan(start,end).prediction({timeFidelity:timeFidelity}).getExtremesPrediction(labels,offsets)},getWaterLevelAtTime:({time})=>{const endDate=new Date(time.getTime()+10*60*1e3);return harmonicsFactory(harmonicsOptions).setTimeSpan(time,endDate).prediction().getTimelinePrediction()[0]}};return tidePrediction};return tidePredictionFactory});
package/package.json CHANGED
@@ -1,45 +1,36 @@
1
1
  {
2
2
  "name": "@neaps/tide-predictor",
3
- "version": "0.0.5",
3
+ "version": "0.1.1",
4
4
  "description": "Tide predictor",
5
- "main": "",
6
5
  "repository": "https://github.com/neaps/tide-predictor",
7
6
  "author": "Kevin Miller <keveemiller@gmail.com>",
8
7
  "license": "MIT",
9
- "module": "./lib/index.es6.js",
10
- "browser": "./dist/tide-predictor.js",
11
- "dependencies": {},
8
+ "type": "module",
9
+ "module": "./src/index.js",
10
+ "browser": "./dist/web/tide-predictor.js",
11
+ "commonjs": "./dist/commonjs/index.js",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./src/index.js",
15
+ "require": "./dist/commonjs/index.js"
16
+ }
17
+ },
12
18
  "devDependencies": {
13
- "@babel/core": "^7.6.2",
14
- "@babel/preset-env": "^7.6.2",
15
- "babel-jest": "^27.2.0",
16
- "babel-preset-env": "^1.7.0",
17
- "eslint": "^7.10.0",
18
- "eslint-config-standard": "^14.1.0",
19
- "eslint-plugin-import": "^2.18.2",
20
- "eslint-plugin-jest": "^24.0.2",
21
- "eslint-plugin-node": "^11.1.0",
22
- "eslint-plugin-promise": "^4.2.1",
23
- "eslint-plugin-standard": "^4.0.1",
24
- "grunt": "^1.4.1",
25
- "grunt-babel": "^8.0.0",
26
- "grunt-contrib-clean": "^2.0.0",
27
- "grunt-contrib-uglify": "^5.0.0",
28
- "grunt-contrib-watch": "^1.1.0",
29
- "grunt-coveralls": "^2.0.0",
30
- "grunt-eslint": "^23.0.0",
31
- "grunt-exec": "^3.0.0",
32
- "jest": "^27.2.0",
33
- "jest-junit": "^11.0.1",
34
- "kind-of": "^6.0.3",
35
- "node-fetch": "^2.6.0",
36
- "rollup-plugin-babel": "^4.3.3",
37
- "rollup-plugin-node-resolve": "^5.2.0"
19
+ "c8": "^7.11.3",
20
+ "eslint": "^8.18.0",
21
+ "mocha": "^10.0.0",
22
+ "npm-run-all": "^4.1.5",
23
+ "rollup-plugin-node-resolve": "^5.2.0",
24
+ "uglify-js": "^3.16.1"
38
25
  },
39
26
  "scripts": {
40
- "test": "BABEL_ENV=test jest",
41
- "coverage": "jest --coverage; grunt coveralls;",
27
+ "test": "mocha --recursive",
42
28
  "lint": "eslint ./src",
43
- "ci": "yarn run lint; jest --ci --runInBand --reporters=default --reporters=jest-junit"
29
+ "coverage": "c8 --reporter=lcov mocha --recursive && codecov",
30
+ "ci": "run-s lint test coverage",
31
+ "build:rollup": "rollup --config rollup.config.js",
32
+ "build:uglify": "uglifyjs ./dist/web/tide-predictor.js -o ./dist/web/tide-predictor.min.js",
33
+ "build:commonDist": "echo \"{\\\"type\\\":\\\"commonjs\\\"}\" > ./dist/commonjs/package.json",
34
+ "build": "run-s build:rollup build:commonDist build:uglify"
44
35
  }
45
36
  }
package/rollup.config.js CHANGED
@@ -9,13 +9,13 @@ export default {
9
9
  file: pkg.browser,
10
10
  format: 'umd'
11
11
  },
12
- { file: pkg.module, format: 'es' }
12
+ { file: pkg.commonjs, format: 'commonjs', exports: 'default' }
13
13
  ],
14
14
  plugins: [
15
15
  resolve({
16
16
  mainFields: ['module', 'main'],
17
17
 
18
- jail: '/src' // Default: '/'
18
+ jail: '/src'
19
19
  })
20
20
  ]
21
21
  }
@@ -1,5 +1,5 @@
1
- import { d2r, r2d } from './constants'
2
- import coefficients from './coefficients'
1
+ import { d2r, r2d } from './constants.js'
2
+ import coefficients from './coefficients.js'
3
3
 
4
4
  // Evaluates a polynomial at argument
5
5
  const polynomial = (coefficients, argument) => {
@@ -139,7 +139,7 @@ const astro = (time) => {
139
139
  pp: coefficients.solarPerigee,
140
140
  90: [90.0],
141
141
  omega: coefficients.terrestrialObliquity,
142
- i: coefficients.lunarInclination,
142
+ i: coefficients.lunarInclination
143
143
  }
144
144
 
145
145
  // Polynomials are in T, that is Julian Centuries; we want our speeds to be
@@ -148,7 +148,7 @@ const astro = (time) => {
148
148
  Object.keys(polynomials).forEach((name) => {
149
149
  result[name] = {
150
150
  value: modulus(polynomial(polynomials[name], T(time)), 360.0),
151
- speed: derivativePolynomial(polynomials[name], T(time)) * dTdHour,
151
+ speed: derivativePolynomial(polynomials[name], T(time)) * dTdHour
152
152
  }
153
153
  })
154
154
 
@@ -160,7 +160,7 @@ const astro = (time) => {
160
160
  xi: _xi,
161
161
  nu: _nu,
162
162
  nup: _nup,
163
- nupp: _nupp,
163
+ nupp: _nupp
164
164
  }
165
165
  Object.keys(functions).forEach((name) => {
166
166
  const functionCall = functions[name]
@@ -169,7 +169,7 @@ const astro = (time) => {
169
169
  functionCall(result.N.value, result.i.value, result.omega.value),
170
170
  360.0
171
171
  ),
172
- speed: null,
172
+ speed: null
173
173
  }
174
174
  })
175
175
 
@@ -178,12 +178,12 @@ const astro = (time) => {
178
178
  // This is in line with convention.
179
179
  const hour = {
180
180
  value: (JD(time) - Math.floor(JD(time))) * 360.0,
181
- speed: 15.0,
181
+ speed: 15.0
182
182
  }
183
183
 
184
184
  result['T+h-s'] = {
185
185
  value: hour.value + result.h.value - result.s.value,
186
- speed: hour.speed + result.h.speed - result.s.speed,
186
+ speed: hour.speed + result.h.speed - result.s.speed
187
187
  }
188
188
 
189
189
  // It is convenient to calculate Schureman's P here since several node
@@ -191,7 +191,7 @@ const astro = (time) => {
191
191
  // (along with I, xi, nu etc) belong somewhere else.
192
192
  result.P = {
193
193
  value: result.p.value - (result.xi.value % 360.0),
194
- speed: null,
194
+ speed: null
195
195
  }
196
196
 
197
197
  return result
@@ -10,9 +10,8 @@ const compoundConstituentFactory = (name, members) => {
10
10
  })
11
11
 
12
12
  const compoundConstituent = {
13
- name: name,
14
-
15
- coefficients: coefficients,
13
+ name,
14
+ coefficients,
16
15
 
17
16
  speed: (astro) => {
18
17
  let speed = 0
@@ -46,7 +45,7 @@ const compoundConstituentFactory = (name, members) => {
46
45
  return f.reduce((previous, value) => {
47
46
  return previous * value
48
47
  })
49
- },
48
+ }
50
49
  }
51
50
 
52
51
  return Object.freeze(compoundConstituent)
@@ -1,4 +1,4 @@
1
- import nodeCorrections from '../node-corrections/index'
1
+ import nodeCorrections from '../node-corrections/index.js'
2
2
 
3
3
  /**
4
4
  * Computes the dot notation of two arrays
@@ -23,7 +23,7 @@ const astronimicDoodsonNumber = (astro) => {
23
23
  astro.p,
24
24
  astro.N,
25
25
  astro.pp,
26
- astro['90'],
26
+ astro['90']
27
27
  ]
28
28
  }
29
29
 
@@ -49,9 +49,8 @@ const constituentFactory = (name, coefficients, u, f) => {
49
49
  }
50
50
 
51
51
  const constituent = {
52
- name: name,
53
-
54
- coefficients: coefficients,
52
+ name,
53
+ coefficients,
55
54
 
56
55
  value: (astro) => {
57
56
  return dotArray(coefficients, astronomicValues(astro))
@@ -63,7 +62,7 @@ const constituentFactory = (name, coefficients, u, f) => {
63
62
 
64
63
  u: typeof u !== 'undefined' ? u : nodeCorrections.uZero,
65
64
 
66
- f: typeof f !== 'undefined' ? f : nodeCorrections.fUnity,
65
+ f: typeof f !== 'undefined' ? f : nodeCorrections.fUnity
67
66
  }
68
67
 
69
68
  return Object.freeze(constituent)