astro-viewer 1.3.0

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 (236) hide show
  1. package/README.md +373 -0
  2. package/dist/astroviewer.cjs +13941 -0
  3. package/dist/astroviewer.cjs.map +1 -0
  4. package/dist/astroviewer.js +2 -0
  5. package/dist/astroviewer.js.map +1 -0
  6. package/dist/astroviewer.min.js +2 -0
  7. package/dist/astroviewer.min.js.map +1 -0
  8. package/lib-esm/AstroSphere.d.ts +114 -0
  9. package/lib-esm/AstroSphere.d.ts.map +1 -0
  10. package/lib-esm/AstroSphere.js +679 -0
  11. package/lib-esm/AstroSphere.js.map +1 -0
  12. package/lib-esm/AstroViewer.d.ts +81 -0
  13. package/lib-esm/AstroViewer.d.ts.map +1 -0
  14. package/lib-esm/AstroViewer.js +348 -0
  15. package/lib-esm/AstroViewer.js.map +1 -0
  16. package/lib-esm/Camera.d.ts +74 -0
  17. package/lib-esm/Camera.d.ts.map +1 -0
  18. package/lib-esm/Camera.js +334 -0
  19. package/lib-esm/Camera.js.map +1 -0
  20. package/lib-esm/Config.d.ts +20 -0
  21. package/lib-esm/Config.d.ts.map +1 -0
  22. package/lib-esm/Config.js +32 -0
  23. package/lib-esm/Config.js.map +1 -0
  24. package/lib-esm/Global.d.ts +27 -0
  25. package/lib-esm/Global.d.ts.map +1 -0
  26. package/lib-esm/Global.js +52 -0
  27. package/lib-esm/Global.js.map +1 -0
  28. package/lib-esm/index.d.ts +17 -0
  29. package/lib-esm/index.d.ts.map +1 -0
  30. package/lib-esm/index.js +16 -0
  31. package/lib-esm/index.js.map +1 -0
  32. package/lib-esm/model/AbstractSkyEntity.d.ts +55 -0
  33. package/lib-esm/model/AbstractSkyEntity.d.ts.map +1 -0
  34. package/lib-esm/model/AbstractSkyEntity.js +153 -0
  35. package/lib-esm/model/AbstractSkyEntity.js.map +1 -0
  36. package/lib-esm/model/AstroGL.d.ts +11 -0
  37. package/lib-esm/model/AstroGL.d.ts.map +1 -0
  38. package/lib-esm/model/AstroGL.js +2 -0
  39. package/lib-esm/model/AstroGL.js.map +1 -0
  40. package/lib-esm/model/ColorMaps.d.ts +17 -0
  41. package/lib-esm/model/ColorMaps.d.ts.map +1 -0
  42. package/lib-esm/model/ColorMaps.js +1288 -0
  43. package/lib-esm/model/ColorMaps.js.map +1 -0
  44. package/lib-esm/model/FoV.d.ts +63 -0
  45. package/lib-esm/model/FoV.d.ts.map +1 -0
  46. package/lib-esm/model/FoV.js +275 -0
  47. package/lib-esm/model/FoV.js.map +1 -0
  48. package/lib-esm/model/MetadataColumn.d.ts +50 -0
  49. package/lib-esm/model/MetadataColumn.d.ts.map +1 -0
  50. package/lib-esm/model/MetadataColumn.js +95 -0
  51. package/lib-esm/model/MetadataColumn.js.map +1 -0
  52. package/lib-esm/model/MetadataManager.d.ts +43 -0
  53. package/lib-esm/model/MetadataManager.d.ts.map +1 -0
  54. package/lib-esm/model/MetadataManager.js +117 -0
  55. package/lib-esm/model/MetadataManager.js.map +1 -0
  56. package/lib-esm/model/Point.d.ts +53 -0
  57. package/lib-esm/model/Point.d.ts.map +1 -0
  58. package/lib-esm/model/Point.js +133 -0
  59. package/lib-esm/model/Point.js.map +1 -0
  60. package/lib-esm/model/Point2D.d.ts +9 -0
  61. package/lib-esm/model/Point2D.d.ts.map +1 -0
  62. package/lib-esm/model/Point2D.js +16 -0
  63. package/lib-esm/model/Point2D.js.map +1 -0
  64. package/lib-esm/model/Source.d.ts +34 -0
  65. package/lib-esm/model/Source.d.ts.map +1 -0
  66. package/lib-esm/model/Source.js +63 -0
  67. package/lib-esm/model/Source.js.map +1 -0
  68. package/lib-esm/model/catalogues/CatalogueGL.d.ts +91 -0
  69. package/lib-esm/model/catalogues/CatalogueGL.d.ts.map +1 -0
  70. package/lib-esm/model/catalogues/CatalogueGL.js +614 -0
  71. package/lib-esm/model/catalogues/CatalogueGL.js.map +1 -0
  72. package/lib-esm/model/catalogues/CatalogueProps.d.ts +2 -0
  73. package/lib-esm/model/catalogues/CatalogueProps.d.ts.map +1 -0
  74. package/lib-esm/model/catalogues/CatalogueProps.js +156 -0
  75. package/lib-esm/model/catalogues/CatalogueProps.js.map +1 -0
  76. package/lib-esm/model/footprints/Footprint.d.ts +44 -0
  77. package/lib-esm/model/footprints/Footprint.d.ts.map +1 -0
  78. package/lib-esm/model/footprints/Footprint.js +104 -0
  79. package/lib-esm/model/footprints/Footprint.js.map +1 -0
  80. package/lib-esm/model/footprints/FootprintProps.d.ts +2 -0
  81. package/lib-esm/model/footprints/FootprintProps.d.ts.map +1 -0
  82. package/lib-esm/model/footprints/FootprintProps.js +87 -0
  83. package/lib-esm/model/footprints/FootprintProps.js.map +1 -0
  84. package/lib-esm/model/footprints/FootprintSetGL.d.ts +106 -0
  85. package/lib-esm/model/footprints/FootprintSetGL.d.ts.map +1 -0
  86. package/lib-esm/model/footprints/FootprintSetGL.js +592 -0
  87. package/lib-esm/model/footprints/FootprintSetGL.js.map +1 -0
  88. package/lib-esm/model/grid/EquatorialGrid.d.ts +49 -0
  89. package/lib-esm/model/grid/EquatorialGrid.d.ts.map +1 -0
  90. package/lib-esm/model/grid/EquatorialGrid.js +302 -0
  91. package/lib-esm/model/grid/EquatorialGrid.js.map +1 -0
  92. package/lib-esm/model/grid/GridTextHelper.d.ts +26 -0
  93. package/lib-esm/model/grid/GridTextHelper.d.ts.map +1 -0
  94. package/lib-esm/model/grid/GridTextHelper.js +92 -0
  95. package/lib-esm/model/grid/GridTextHelper.js.map +1 -0
  96. package/lib-esm/model/grid/HealpixGrid.d.ts +49 -0
  97. package/lib-esm/model/grid/HealpixGrid.d.ts.map +1 -0
  98. package/lib-esm/model/grid/HealpixGrid.js +306 -0
  99. package/lib-esm/model/grid/HealpixGrid.js.map +1 -0
  100. package/lib-esm/model/hips/AllSky.d.ts +40 -0
  101. package/lib-esm/model/hips/AllSky.d.ts.map +1 -0
  102. package/lib-esm/model/hips/AllSky.js +232 -0
  103. package/lib-esm/model/hips/AllSky.js.map +1 -0
  104. package/lib-esm/model/hips/AncestorTile.d.ts +38 -0
  105. package/lib-esm/model/hips/AncestorTile.d.ts.map +1 -0
  106. package/lib-esm/model/hips/AncestorTile.js +248 -0
  107. package/lib-esm/model/hips/AncestorTile.js.map +1 -0
  108. package/lib-esm/model/hips/FoVHelper.d.ts +11 -0
  109. package/lib-esm/model/hips/FoVHelper.d.ts.map +1 -0
  110. package/lib-esm/model/hips/FoVHelper.js +107 -0
  111. package/lib-esm/model/hips/FoVHelper.js.map +1 -0
  112. package/lib-esm/model/hips/HiPS.d.ts +47 -0
  113. package/lib-esm/model/hips/HiPS.d.ts.map +1 -0
  114. package/lib-esm/model/hips/HiPS.js +222 -0
  115. package/lib-esm/model/hips/HiPS.js.map +1 -0
  116. package/lib-esm/model/hips/HiPSDescriptor.d.ts +37 -0
  117. package/lib-esm/model/hips/HiPSDescriptor.d.ts.map +1 -0
  118. package/lib-esm/model/hips/HiPSDescriptor.js +132 -0
  119. package/lib-esm/model/hips/HiPSDescriptor.js.map +1 -0
  120. package/lib-esm/model/hips/Tile.d.ts +51 -0
  121. package/lib-esm/model/hips/Tile.d.ts.map +1 -0
  122. package/lib-esm/model/hips/Tile.js +355 -0
  123. package/lib-esm/model/hips/Tile.js.map +1 -0
  124. package/lib-esm/model/hips/TileBuffer.d.ts +39 -0
  125. package/lib-esm/model/hips/TileBuffer.d.ts.map +1 -0
  126. package/lib-esm/model/hips/TileBuffer.js +148 -0
  127. package/lib-esm/model/hips/TileBuffer.js.map +1 -0
  128. package/lib-esm/model/hips/VisibleTilesManager.d.ts +35 -0
  129. package/lib-esm/model/hips/VisibleTilesManager.d.ts.map +1 -0
  130. package/lib-esm/model/hips/VisibleTilesManager.js +160 -0
  131. package/lib-esm/model/hips/VisibleTilesManager.js.map +1 -0
  132. package/lib-esm/model/tap/TapMetadata.d.ts +31 -0
  133. package/lib-esm/model/tap/TapMetadata.d.ts.map +1 -0
  134. package/lib-esm/model/tap/TapMetadata.js +55 -0
  135. package/lib-esm/model/tap/TapMetadata.js.map +1 -0
  136. package/lib-esm/model/tap/TapMetadataList.d.ts +23 -0
  137. package/lib-esm/model/tap/TapMetadataList.d.ts.map +1 -0
  138. package/lib-esm/model/tap/TapMetadataList.js +58 -0
  139. package/lib-esm/model/tap/TapMetadataList.js.map +1 -0
  140. package/lib-esm/model/tap/TapRepo.d.ts +27 -0
  141. package/lib-esm/model/tap/TapRepo.d.ts.map +1 -0
  142. package/lib-esm/model/tap/TapRepo.js +51 -0
  143. package/lib-esm/model/tap/TapRepo.js.map +1 -0
  144. package/lib-esm/services/SesameService.d.ts +14 -0
  145. package/lib-esm/services/SesameService.d.ts.map +1 -0
  146. package/lib-esm/services/SesameService.js +54 -0
  147. package/lib-esm/services/SesameService.js.map +1 -0
  148. package/lib-esm/services/helpers.d.ts +5 -0
  149. package/lib-esm/services/helpers.d.ts.map +1 -0
  150. package/lib-esm/services/helpers.js +16 -0
  151. package/lib-esm/services/helpers.js.map +1 -0
  152. package/lib-esm/services/hipsNodeService.d.ts +7 -0
  153. package/lib-esm/services/hipsNodeService.d.ts.map +1 -0
  154. package/lib-esm/services/hipsNodeService.js +65 -0
  155. package/lib-esm/services/hipsNodeService.js.map +1 -0
  156. package/lib-esm/services/parse-hipslist.d.ts +3 -0
  157. package/lib-esm/services/parse-hipslist.d.ts.map +1 -0
  158. package/lib-esm/services/parse-hipslist.js +25 -0
  159. package/lib-esm/services/parse-hipslist.js.map +1 -0
  160. package/lib-esm/services/queryCatalogueByFoV.d.ts +2 -0
  161. package/lib-esm/services/queryCatalogueByFoV.d.ts.map +1 -0
  162. package/lib-esm/services/queryCatalogueByFoV.js +56 -0
  163. package/lib-esm/services/queryCatalogueByFoV.js.map +1 -0
  164. package/lib-esm/services/queryFootprintSetByFov.d.ts +2 -0
  165. package/lib-esm/services/queryFootprintSetByFov.d.ts.map +1 -0
  166. package/lib-esm/services/queryFootprintSetByFov.js +128 -0
  167. package/lib-esm/services/queryFootprintSetByFov.js.map +1 -0
  168. package/lib-esm/services/tapRepoService.d.ts +2 -0
  169. package/lib-esm/services/tapRepoService.d.ts.map +1 -0
  170. package/lib-esm/services/tapRepoService.js +190 -0
  171. package/lib-esm/services/tapRepoService.js.map +1 -0
  172. package/lib-esm/services/types.d.ts +13 -0
  173. package/lib-esm/services/types.d.ts.map +1 -0
  174. package/lib-esm/services/types.js +2 -0
  175. package/lib-esm/services/types.js.map +1 -0
  176. package/lib-esm/shader/CatalogueShaderProgram.d.ts +35 -0
  177. package/lib-esm/shader/CatalogueShaderProgram.d.ts.map +1 -0
  178. package/lib-esm/shader/CatalogueShaderProgram.js +94 -0
  179. package/lib-esm/shader/CatalogueShaderProgram.js.map +1 -0
  180. package/lib-esm/shader/FootprintShaderProgram.d.ts +31 -0
  181. package/lib-esm/shader/FootprintShaderProgram.d.ts.map +1 -0
  182. package/lib-esm/shader/FootprintShaderProgram.js +86 -0
  183. package/lib-esm/shader/FootprintShaderProgram.js.map +1 -0
  184. package/lib-esm/shader/GridShaderManager.d.ts +6 -0
  185. package/lib-esm/shader/GridShaderManager.d.ts.map +1 -0
  186. package/lib-esm/shader/GridShaderManager.js +29 -0
  187. package/lib-esm/shader/GridShaderManager.js.map +1 -0
  188. package/lib-esm/shader/HiPSShaderProgram.d.ts +54 -0
  189. package/lib-esm/shader/HiPSShaderProgram.d.ts.map +1 -0
  190. package/lib-esm/shader/HiPSShaderProgram.js +257 -0
  191. package/lib-esm/shader/HiPSShaderProgram.js.map +1 -0
  192. package/lib-esm/shader/ShaderManager.d.ts +12 -0
  193. package/lib-esm/shader/ShaderManager.d.ts.map +1 -0
  194. package/lib-esm/shader/ShaderManager.js +344 -0
  195. package/lib-esm/shader/ShaderManager.js.map +1 -0
  196. package/lib-esm/shader/ShaderManagerMutliHiPS.d.ts +12 -0
  197. package/lib-esm/shader/ShaderManagerMutliHiPS.d.ts.map +1 -0
  198. package/lib-esm/shader/ShaderManagerMutliHiPS.js +750 -0
  199. package/lib-esm/shader/ShaderManagerMutliHiPS.js.map +1 -0
  200. package/lib-esm/utils/CoordsType.d.ts +10 -0
  201. package/lib-esm/utils/CoordsType.d.ts.map +1 -0
  202. package/lib-esm/utils/CoordsType.js +12 -0
  203. package/lib-esm/utils/CoordsType.js.map +1 -0
  204. package/lib-esm/utils/FoVUtils.d.ts +46 -0
  205. package/lib-esm/utils/FoVUtils.d.ts.map +1 -0
  206. package/lib-esm/utils/FoVUtils.js +217 -0
  207. package/lib-esm/utils/FoVUtils.js.map +1 -0
  208. package/lib-esm/utils/GeomUtils.d.ts +36 -0
  209. package/lib-esm/utils/GeomUtils.d.ts.map +1 -0
  210. package/lib-esm/utils/GeomUtils.js +267 -0
  211. package/lib-esm/utils/GeomUtils.js.map +1 -0
  212. package/lib-esm/utils/MouseHelper.d.ts +36 -0
  213. package/lib-esm/utils/MouseHelper.d.ts.map +1 -0
  214. package/lib-esm/utils/MouseHelper.js +94 -0
  215. package/lib-esm/utils/MouseHelper.js.map +1 -0
  216. package/lib-esm/utils/PerspectiveMatrixManager.d.ts +11 -0
  217. package/lib-esm/utils/PerspectiveMatrixManager.d.ts.map +1 -0
  218. package/lib-esm/utils/PerspectiveMatrixManager.js +37 -0
  219. package/lib-esm/utils/PerspectiveMatrixManager.js.map +1 -0
  220. package/lib-esm/utils/RayPickingUtils.d.ts +30 -0
  221. package/lib-esm/utils/RayPickingUtils.d.ts.map +1 -0
  222. package/lib-esm/utils/RayPickingUtils.js +112 -0
  223. package/lib-esm/utils/RayPickingUtils.js.map +1 -0
  224. package/lib-esm/utils/STCSParser.d.ts +16 -0
  225. package/lib-esm/utils/STCSParser.d.ts.map +1 -0
  226. package/lib-esm/utils/STCSParser.js +96 -0
  227. package/lib-esm/utils/STCSParser.js.map +1 -0
  228. package/lib-esm/utils/ShaderUtility.d.ts +2 -0
  229. package/lib-esm/utils/ShaderUtility.d.ts.map +1 -0
  230. package/lib-esm/utils/ShaderUtility.js +23 -0
  231. package/lib-esm/utils/ShaderUtility.js.map +1 -0
  232. package/lib-esm/utils/Utils.d.ts +32 -0
  233. package/lib-esm/utils/Utils.d.ts.map +1 -0
  234. package/lib-esm/utils/Utils.js +77 -0
  235. package/lib-esm/utils/Utils.js.map +1 -0
  236. package/package.json +82 -0
@@ -0,0 +1,679 @@
1
+ import { bootSetup } from './Config.js';
2
+ import Camera from './Camera.js';
3
+ import RayPickingUtils from './utils/RayPickingUtils.js';
4
+ import global from './Global.js';
5
+ import MouseHelper from './utils/MouseHelper.js';
6
+ import { cartesianToSpherical, sphericalToAstroDeg, raDegToHMS, decDegToDMS, } from './utils/Utils.js';
7
+ import { HiPS } from './model/hips/HiPS.js';
8
+ import { PerspectiveMatrixManager } from './utils/PerspectiveMatrixManager.js';
9
+ import { Point } from './model/Point.js';
10
+ import { FoVUtils } from './utils/FoVUtils.js';
11
+ import { EquatorialGrid } from './model/grid/EquatorialGrid.js';
12
+ import { HealpixGrid } from './model/grid/HealpixGrid.js';
13
+ import { CoordsType } from './utils/CoordsType.js';
14
+ import ColorMaps from './model/ColorMaps.js';
15
+ /**
16
+ * AstroSphere — main WebGL scene controller (TS port)
17
+ */
18
+ class AstroSphere {
19
+ static MIN_WHEEL_SCALE = 0.85;
20
+ static MAX_WHEEL_SCALE = 1.8;
21
+ _camera;
22
+ _perspectiveMatrixManager;
23
+ centralPoinCoords;
24
+ mousePointCoords;
25
+ canvas;
26
+ _healpixGrid;
27
+ _equatorialGrid;
28
+ mouseHelper;
29
+ mouseDown = false;
30
+ lastMouseX = null;
31
+ lastMouseY = null;
32
+ inertiaX = 0.0;
33
+ inertiaY = 0.0;
34
+ zoomInertia = 0.0;
35
+ pointerDownX = null;
36
+ pointerDownY = null;
37
+ pointerDownAt = 0;
38
+ _activeHiPS = null;
39
+ startup = true;
40
+ fov;
41
+ activeCatalogues = [];
42
+ activeFootprintSets = [];
43
+ _webgl;
44
+ _selectedColorMap;
45
+ _cameraStatusChanged = false;
46
+ lastHoveredSource = null;
47
+ lastHoveredCatalogue = null;
48
+ zoomSensitivity = 1.0;
49
+ constructor(canvas, webgl) {
50
+ console.log('[AstroSphere] new instance for canvas', canvas.id);
51
+ // Keep global GL context (as in original JS)
52
+ this._webgl = webgl;
53
+ this.mouseHelper = new MouseHelper();
54
+ this.canvas = canvas;
55
+ const nativeColorMap = 'native';
56
+ this._selectedColorMap = ColorMaps[nativeColorMap];
57
+ global.insideSphere = bootSetup.insideSphere;
58
+ this.initCamera();
59
+ this._healpixGrid = new HealpixGrid(this._webgl);
60
+ this._perspectiveMatrixManager = new PerspectiveMatrixManager(canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, bootSetup.insideSphere);
61
+ this._perspectiveMatrixManager.computePerspectiveMatrix(canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, bootSetup.insideSphere);
62
+ this._equatorialGrid = new EquatorialGrid(this._webgl, this._healpixGrid);
63
+ this._equatorialGrid.init(this._healpixGrid.getMinFoV());
64
+ this.updateCentralPoint();
65
+ this.startup = true;
66
+ this.addEventListeners(canvas);
67
+ this.fov = this._healpixGrid.refreshFoV(this._camera, this._perspectiveMatrixManager.pMatrix);
68
+ this._camera.refreshFoV(this.fov.minFoV);
69
+ }
70
+ initCamera() {
71
+ if (bootSetup.insideSphere) {
72
+ this._camera = new Camera([0.0, 0.0, -0.005], true);
73
+ }
74
+ else {
75
+ this._camera = new Camera([0.0, 0.0, 4.0], false);
76
+ }
77
+ }
78
+ setCamera(camera) {
79
+ this._camera = camera;
80
+ }
81
+ setCameraRotationSensitivity(value) {
82
+ this._camera.setRotationSensitivity(value);
83
+ }
84
+ getCameraRotationSensitivity() {
85
+ return this._camera.getRotationSensitivity();
86
+ }
87
+ get healpixGrid() {
88
+ return this._healpixGrid;
89
+ }
90
+ get equatorialGrid() {
91
+ return this._equatorialGrid;
92
+ }
93
+ // This is a lickely a duplication of FoVUtils.getCenterJ2000(this.canvas)
94
+ updateCentralPoint() {
95
+ const sphericalCoords = this.getPhiThetaDeg(this.canvas);
96
+ const astroCoords = sphericalToAstroDeg(sphericalCoords.phi, sphericalCoords.theta);
97
+ const raHMS = raDegToHMS(astroCoords.ra);
98
+ const decDMS = decDegToDMS(astroCoords.dec);
99
+ this.centralPoinCoords = {
100
+ astroDeg: astroCoords,
101
+ sphericalDeg: sphericalCoords,
102
+ raHMS: raHMS,
103
+ decDMS: decDMS
104
+ };
105
+ return this.centralPoinCoords;
106
+ }
107
+ updateLastMousePoint() {
108
+ const sphericalCoords = { phi: this.mouseHelper.phi, theta: this.mouseHelper.theta };
109
+ const astroCoords = { ra: this.mouseHelper.ra, dec: this.mouseHelper.dec };
110
+ const raHMS = this.mouseHelper.raHMS;
111
+ const decDMS = this.mouseHelper.decDMS;
112
+ this.mousePointCoords = {
113
+ astroDeg: astroCoords,
114
+ sphericalDeg: sphericalCoords,
115
+ raHMS: raHMS,
116
+ decDMS: decDMS
117
+ };
118
+ return this.mousePointCoords;
119
+ }
120
+ clearLastMousePoint() {
121
+ this.mousePointCoords = undefined;
122
+ }
123
+ // This should call FoVUtils.getJ200Centre(this.canvas)
124
+ getCentralPointCoordinates() {
125
+ return this.centralPoinCoords;
126
+ }
127
+ getLastMousePointCoordinates() {
128
+ return this.mousePointCoords;
129
+ }
130
+ clamp(value, min, max) {
131
+ return Math.min(max, Math.max(min, value));
132
+ }
133
+ computeZoomStep(currentFov, deltaY) {
134
+ const direction = deltaY < 0 ? -1 : 1;
135
+ const wheelScale = this.clamp(Math.abs(deltaY) / 120, AstroSphere.MIN_WHEEL_SCALE, AstroSphere.MAX_WHEEL_SCALE);
136
+ // Continuous wheel response:
137
+ // - broad FoV stays responsive without large jumps
138
+ // - narrow FoV keeps a usable floor to avoid the 0.1 -> 0.02 deg stall
139
+ const baseMagnitude = this.clamp(0.0012 + 0.0025 * Math.sqrt(Math.max(currentFov, 0)), 0.0012, 0.04);
140
+ return direction * baseMagnitude * wheelScale * this.zoomSensitivity;
141
+ }
142
+ setZoomSensitivity(value) {
143
+ this.zoomSensitivity = this.clamp(value, 0.2, 3);
144
+ }
145
+ getZoomSensitivity() {
146
+ return this.zoomSensitivity;
147
+ }
148
+ emitCameraChanged(reason) {
149
+ // avoid dispatch before scene is ready
150
+ if (!this._activeHiPS)
151
+ return;
152
+ if (!this._healpixGrid?.fovObj)
153
+ return;
154
+ const detail = this.getCurrentStatus();
155
+ if (!detail)
156
+ return;
157
+ // optional debug
158
+ // console.log('[AstroSphere] emit camera-changed:', reason);
159
+ this.canvas.dispatchEvent(new CustomEvent('camera-changed', {
160
+ detail,
161
+ bubbles: true,
162
+ composed: true,
163
+ }));
164
+ }
165
+ addEventListeners(canvas) {
166
+ if (global.debug) {
167
+ console.log('[AstroSphere::addEventListeners]');
168
+ }
169
+ const CLICK_MAX_DISTANCE_PX = 4;
170
+ const CLICK_MAX_DURATION_MS = 250;
171
+ const rect = canvas.getBoundingClientRect();
172
+ this.lastMouseX = rect.left; // locale al canvas
173
+ this.lastMouseY = rect.top;
174
+ const handleMouseDown = (event) => {
175
+ canvas.setPointerCapture(event.pointerId);
176
+ this.mouseDown = true;
177
+ const rect = canvas.getBoundingClientRect();
178
+ this.lastMouseX = event.clientX - rect.left; // locale al canvas
179
+ this.lastMouseY = event.clientY - rect.top; // locale al canvas
180
+ this.pointerDownX = this.lastMouseX;
181
+ this.pointerDownY = this.lastMouseY;
182
+ this.pointerDownAt = Date.now();
183
+ const mousePoint = RayPickingUtils.getIntersectionPointWithSingleModel(this.lastMouseX, this.lastMouseY, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
184
+ if (mousePoint && mousePoint.length > 0) {
185
+ this.mouseHelper.update(mousePoint);
186
+ this.updateLastMousePoint();
187
+ }
188
+ else {
189
+ this.clearLastMousePoint();
190
+ }
191
+ event.preventDefault();
192
+ return false;
193
+ };
194
+ const handleMouseUp = (event) => {
195
+ canvas.releasePointerCapture(event.pointerId);
196
+ this.mouseDown = false;
197
+ document.body.style.cursor = 'auto';
198
+ if (event.button !== 0) {
199
+ event.preventDefault();
200
+ return false;
201
+ }
202
+ const rect = canvas.getBoundingClientRect();
203
+ const localX = event.clientX - rect.left;
204
+ const localY = event.clientY - rect.top;
205
+ this.lastMouseX = localX;
206
+ this.lastMouseY = localY;
207
+ const moveDist = Math.hypot(localX - (this.pointerDownX ?? localX), localY - (this.pointerDownY ?? localY));
208
+ const elapsedMs = Date.now() - this.pointerDownAt;
209
+ const isClick = moveDist <= CLICK_MAX_DISTANCE_PX && elapsedMs <= CLICK_MAX_DURATION_MS;
210
+ if (isClick) {
211
+ const mousePoint = RayPickingUtils.getIntersectionPointWithSingleModel(localX, localY, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
212
+ if (mousePoint && mousePoint.length > 0) {
213
+ this.mouseHelper.update(mousePoint);
214
+ this.updateLastMousePoint();
215
+ for (const cat of this.activeCatalogues) {
216
+ const clickResult = cat.selectPrimarySourceFromClick(this.mouseHelper);
217
+ if (!clickResult?.sources.length)
218
+ continue;
219
+ this._webgl.canvas.dispatchEvent(new CustomEvent('source-clicked', {
220
+ detail: {
221
+ source: clickResult.sources,
222
+ selectionState: clickResult.selectionState,
223
+ catalogue: cat,
224
+ },
225
+ bubbles: true,
226
+ composed: true,
227
+ }));
228
+ }
229
+ for (const fset of this.activeFootprintSets) {
230
+ const clickResult = fset.selectPrimaryFootprintFromClick(this.mouseHelper);
231
+ if (!clickResult?.footprints.length)
232
+ continue;
233
+ this._webgl.canvas.dispatchEvent(new CustomEvent('footprint-clicked', {
234
+ detail: {
235
+ footprint: clickResult.footprints,
236
+ selectionState: clickResult.selectionState,
237
+ footprintSet: fset,
238
+ },
239
+ bubbles: true,
240
+ composed: true,
241
+ }));
242
+ }
243
+ }
244
+ }
245
+ else {
246
+ this.clearLastMousePoint();
247
+ }
248
+ };
249
+ const handleMouseMove = (event) => {
250
+ const rect = canvas.getBoundingClientRect();
251
+ // 🔹 canvas-local coordinates
252
+ const localX = event.clientX - rect.left;
253
+ const localY = event.clientY - rect.top;
254
+ const newX = localX;
255
+ const newY = localY;
256
+ // if (!healpixGridSingleton) return;
257
+ if (!this._healpixGrid)
258
+ return;
259
+ if (this.mouseDown) {
260
+ document.body.style.cursor = 'grab';
261
+ // Rotation deltas – either use client-space or local-space, but be consistent
262
+ const deltaX = ((newX - (this.lastMouseX ?? newX)) * Math.PI) / canvas.width;
263
+ const deltaY = ((newY - (this.lastMouseY ?? newY)) * Math.PI) / canvas.height;
264
+ this.inertiaX += 0.1 * deltaX;
265
+ this.inertiaY += 0.1 * deltaY;
266
+ this.updateCentralPoint();
267
+ }
268
+ else {
269
+ // Use canvas-local coords for picking
270
+ const mousePoint = RayPickingUtils.getIntersectionPointWithSingleModel(localX, localY, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
271
+ if (mousePoint && mousePoint.length > 0) {
272
+ this.mouseHelper.update(mousePoint);
273
+ this.updateLastMousePoint();
274
+ }
275
+ else {
276
+ this.clearLastMousePoint();
277
+ }
278
+ }
279
+ if (!this.centralPoinCoords) {
280
+ this.updateCentralPoint();
281
+ }
282
+ this.lastMouseX = newX;
283
+ this.lastMouseY = newY;
284
+ this._cameraStatusChanged = true;
285
+ this.emitCameraChanged('pointermove');
286
+ event.preventDefault();
287
+ };
288
+ const handleMouseWheel = (event) => {
289
+ const currentFov = this._healpixGrid.getMinFoV();
290
+ const zoomStep = this.computeZoomStep(currentFov, event.deltaY);
291
+ // Apply wheel zoom immediately and discard any queued inertia so reversing
292
+ // direction feels responsive instead of "buffered".
293
+ this.zoomInertia = 0;
294
+ this._camera.zoom(zoomStep);
295
+ this.fov = this._healpixGrid.refreshFoV(this._camera, this._perspectiveMatrixManager.pMatrix);
296
+ this._camera.refreshFoV(this.fov.minFoV);
297
+ this._cameraStatusChanged = true;
298
+ this.emitCameraChanged('wheel');
299
+ event.preventDefault();
300
+ };
301
+ const handleContextMenu = (event) => {
302
+ event.preventDefault();
303
+ const rect = canvas.getBoundingClientRect();
304
+ const localX = event.clientX - rect.left;
305
+ const localY = event.clientY - rect.top;
306
+ const mousePoint = RayPickingUtils.getIntersectionPointWithSingleModel(localX, localY, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
307
+ if (!mousePoint || mousePoint.length === 0) {
308
+ return false;
309
+ }
310
+ this.mouseHelper.update(mousePoint);
311
+ this.updateLastMousePoint();
312
+ for (const cat of this.activeCatalogues) {
313
+ const pickResult = cat.getSourcesFromPointer(this.mouseHelper);
314
+ if (!pickResult?.sources.length)
315
+ continue;
316
+ this._webgl.canvas.dispatchEvent(new CustomEvent('source-contextmenu', {
317
+ detail: {
318
+ source: pickResult.sources,
319
+ catalogue: cat,
320
+ clientX: event.clientX,
321
+ clientY: event.clientY,
322
+ },
323
+ bubbles: true,
324
+ composed: true,
325
+ }));
326
+ break;
327
+ }
328
+ for (const fset of this.activeFootprintSets) {
329
+ const pickResult = fset.getFootprintsFromPointer(this.mouseHelper);
330
+ if (!pickResult?.footprints.length)
331
+ continue;
332
+ this._webgl.canvas.dispatchEvent(new CustomEvent('footprint-contextmenu', {
333
+ detail: {
334
+ footprint: pickResult.footprints,
335
+ footprintSet: fset,
336
+ clientX: event.clientX,
337
+ clientY: event.clientY,
338
+ },
339
+ bubbles: true,
340
+ composed: true,
341
+ }));
342
+ break;
343
+ }
344
+ return false;
345
+ };
346
+ const onKeyDown = (evt) => {
347
+ if (!evt.ctrlKey) {
348
+ return;
349
+ }
350
+ // console.log('[AstroSphere::onKeyDown] key=', evt.key)
351
+ switch (evt.key) {
352
+ case '1':
353
+ // Free camera
354
+ this._camera.clearRotationLock();
355
+ break;
356
+ case '2':
357
+ // Lock X axis rotation
358
+ this._camera.setRotationLock({ x: true, y: false, z: false });
359
+ break;
360
+ case '3':
361
+ // Lock Y axis rotation
362
+ this._camera.setRotationLock({ x: false, y: true, z: false });
363
+ break;
364
+ case '4':
365
+ // Lock Z axis rotation
366
+ this._camera.setRotationLock({ x: false, y: false, z: true });
367
+ break;
368
+ }
369
+ };
370
+ console.log('[AstroSphere] registering pointer and wheel listeners on canvas');
371
+ canvas.onpointerdown = handleMouseDown;
372
+ canvas.onpointerup = handleMouseUp;
373
+ canvas.onpointermove = handleMouseMove;
374
+ canvas.onpointerleave = () => {
375
+ this.clearLastMousePoint();
376
+ this._cameraStatusChanged = true;
377
+ this.emitCameraChanged('pointerleave');
378
+ };
379
+ console.log('[AstroSphere] adding wheel event listener with passive: false');
380
+ canvas.addEventListener('wheel', handleMouseWheel, { passive: false });
381
+ canvas.addEventListener('contextmenu', handleContextMenu);
382
+ console.log('[AstroSphere] registering global keydown listener on document');
383
+ document.addEventListener('keydown', onKeyDown, { capture: true });
384
+ }
385
+ // REVIEW THIS METHOD AND MOVE IT
386
+ getPhiThetaDeg(canvas) {
387
+ const rect = canvas.getBoundingClientRect();
388
+ const maxX = rect.width;
389
+ const maxY = rect.height;
390
+ const pickerPoint = RayPickingUtils.getIntersectionPointWithSingleModel(maxX / 2, maxY / 2, this._healpixGrid, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
391
+ return cartesianToSpherical(pickerPoint);
392
+ }
393
+ activateHiPS(hipsDescriptor) {
394
+ this._activeHiPS = new HiPS(1, [0.0, 0.0, 0.0], 0, 0, hipsDescriptor, this._webgl, this._healpixGrid);
395
+ }
396
+ // Catalogue section
397
+ async showCatalogue(cat) {
398
+ // console.log(cat)
399
+ if (cat)
400
+ this.activeCatalogues.push(cat);
401
+ return cat;
402
+ }
403
+ deleteCatalogue(catalogue) {
404
+ this.activeCatalogues = this.activeCatalogues.filter(c => c !== catalogue);
405
+ }
406
+ // End Catalogue section
407
+ // Footprint section
408
+ async showFootprintSet(fset) {
409
+ // console.log(fset)
410
+ if (fset)
411
+ this.activeFootprintSets.push(fset);
412
+ return fset;
413
+ }
414
+ deleteFootprintSet(footprintSet) {
415
+ this.activeFootprintSets = this.activeFootprintSets.filter(fst => fst !== footprintSet);
416
+ }
417
+ getHoveredFootprints() {
418
+ let footprintsHovered = [];
419
+ this.activeFootprintSets.forEach(fset => {
420
+ footprintsHovered.push(fset.hoveredFootprints);
421
+ });
422
+ return footprintsHovered;
423
+ }
424
+ // End Footprint section
425
+ goTo(raDeg, decDeg) {
426
+ this._camera.goTo(raDeg, decDeg);
427
+ }
428
+ getFoV() {
429
+ return this.fov;
430
+ }
431
+ getFoVPolygon() {
432
+ if (this.healpixGrid == null)
433
+ throw new Error(`healpixGrid is ${this.healpixGrid}`);
434
+ return FoVUtils.getFoVPolygon(this._camera, this.canvas, this._healpixGrid, this._healpixGrid, this._webgl, this._perspectiveMatrixManager.pMatrix);
435
+ }
436
+ changeFoV(deg) {
437
+ const distance = this._healpixGrid.getFoV().computeDistanceFromAngle(deg);
438
+ this._camera.translate(distance);
439
+ this.fov = this._healpixGrid.refreshFoV(this._camera, this._perspectiveMatrixManager.pMatrix);
440
+ this._camera.refreshFoV(this.fov.minFoV);
441
+ }
442
+ changeFoV2(deg) {
443
+ const newCameraPos = this._healpixGrid.getFoV().computeCameraPositionForFoV(deg);
444
+ this._camera.setCameraPosition(newCameraPos);
445
+ }
446
+ changeFoV3(deg) {
447
+ const newPos = this._healpixGrid.getFoV().computeCameraPositionForAngularDiameter(deg);
448
+ this._camera.setCameraPosition(newPos);
449
+ // Recompute projection after moving the camera
450
+ this._perspectiveMatrixManager.computePerspectiveMatrix(this.canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, false);
451
+ }
452
+ getInsideSphere() {
453
+ return global.insideSphere;
454
+ }
455
+ toggleInsideSphere() {
456
+ global.insideSphere = !global.insideSphere;
457
+ // console.log(global.insideSphere)
458
+ this._camera.toggleInsideSphere();
459
+ }
460
+ // imposta posizione camera
461
+ setCameraPosition(pos) {
462
+ this._camera.setCameraPosition(pos);
463
+ this._perspectiveMatrixManager.computePerspectiveMatrix(this.canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, global.insideSphere);
464
+ }
465
+ // imposta orientamento camera tramite view matrix
466
+ setCameraMatrix(viewMatrix) {
467
+ this._camera.setCameraMatrix(viewMatrix);
468
+ this._perspectiveMatrixManager.computePerspectiveMatrix(this.canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, global.insideSphere);
469
+ }
470
+ _refreshingStatus = false;
471
+ // set completo camera (pos + orientamento)
472
+ applyFullCameraState(detail, applyColor) {
473
+ this._refreshingStatus = true;
474
+ this._camera = detail.camera;
475
+ // this.goTo(detail.centralPoint.raDeg, detail.centralPoint.decDeg)
476
+ this._healpixGrid.setModelMatrix(detail.mMatrix);
477
+ this._perspectiveMatrixManager.pMatrix = detail.pMatrix;
478
+ this.setCameraMatrix(detail.vMatrix);
479
+ // this.goTo(detail.centralPoint.raDeg, detail.centralPoint.decDeg)
480
+ if (applyColor) {
481
+ this._activeHiPS?.changeColorMap(detail.colorMap);
482
+ }
483
+ this._refreshingStatus = false;
484
+ }
485
+ getCurrentStatus() {
486
+ this.updateCentralPoint();
487
+ const centralradeg = this.centralPoinCoords?.astroDeg.ra;
488
+ const centraldecdeg = this.centralPoinCoords?.astroDeg.dec;
489
+ // if (!centraldecdeg || !centralradeg) {
490
+ if (centralradeg == null || centraldecdeg == null) {
491
+ return null;
492
+ }
493
+ // if (this._rotating && centraldecdeg && centralradeg) {
494
+ const detail = {
495
+ fovDeg: this.fov.minFoV,
496
+ fovXDeg: this.fov.xFoV,
497
+ fovYDeg: this.fov.yFoV,
498
+ position: this._camera.getCameraPosition(),
499
+ vMatrix: this._camera.getCameraMatrix(),
500
+ pMatrix: this._perspectiveMatrixManager.pMatrix,
501
+ mMatrix: this._healpixGrid.getModelMatrix(),
502
+ camera: this._camera,
503
+ timestamp: performance.now(),
504
+ centralPoint: new Point({ raDeg: centralradeg, decDeg: centraldecdeg }, CoordsType.ASTRO),
505
+ mouseHoverPoint: this.mousePointCoords,
506
+ colorMap: this._selectedColorMap,
507
+ getFoVPolygon: this.getFoVPolygon(),
508
+ };
509
+ return detail;
510
+ // }
511
+ // return null
512
+ }
513
+ changeColorMap(cm) {
514
+ if (!this._activeHiPS)
515
+ return;
516
+ this._selectedColorMap = cm;
517
+ this._activeHiPS?.changeColorMap(cm);
518
+ }
519
+ prevFov = 0;
520
+ prevCentralRaDeg = null;
521
+ prevCentralDecDeg = null;
522
+ get activeHiPS() {
523
+ return this._activeHiPS;
524
+ }
525
+ draw(canvas) {
526
+ if (this._refreshingStatus)
527
+ return;
528
+ if (!this._webgl)
529
+ return;
530
+ if (!this._activeHiPS)
531
+ return;
532
+ if (!this._healpixGrid || Object.keys(this._healpixGrid).length === 0)
533
+ return;
534
+ if (this._healpixGrid.fovObj === undefined)
535
+ return;
536
+ // In WebGL2, OES_element_index_uint is core, no need to fetch the extension each frame.
537
+ // global.gl.getExtension('OES_element_index_uint')
538
+ // global.gl.clear(global.gl.COLOR_BUFFER_BIT | global.gl.DEPTH_BUFFER_BIT)
539
+ this._perspectiveMatrixManager.computePerspectiveMatrix(canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, global.insideSphere);
540
+ let cameraRotated = false;
541
+ let THETA = 0;
542
+ let PHI = 0;
543
+ this._webgl.viewport(0, 0, this._webgl.drawingBufferWidth, this._webgl.drawingBufferHeight);
544
+ this._webgl.clear(this._webgl.COLOR_BUFFER_BIT | this._webgl.DEPTH_BUFFER_BIT);
545
+ // Zoom inertia
546
+ if (this.zoomInertia !== 0) {
547
+ if (Math.abs(this.zoomInertia) > 0.0001) {
548
+ this._camera.zoom(this.zoomInertia);
549
+ this.zoomInertia *= 0.95;
550
+ this.fov = this._healpixGrid.refreshFoV(this._camera, this._perspectiveMatrixManager.pMatrix);
551
+ this._camera.refreshFoV(this.fov.minFoV);
552
+ if (this.prevFov !== this.fov.minFoV) {
553
+ if (!this.centralPoinCoords) {
554
+ this.centralPoinCoords = this.updateCentralPoint();
555
+ }
556
+ this.prevFov = this.fov.minFoV;
557
+ }
558
+ }
559
+ else {
560
+ this.zoomInertia = 0;
561
+ }
562
+ this._cameraStatusChanged = true;
563
+ }
564
+ // Rotation inertia
565
+ if (this.mouseDown || Math.abs(this.inertiaX) > 0.02 || Math.abs(this.inertiaY) > 0.02) {
566
+ cameraRotated = true;
567
+ THETA = this.inertiaY;
568
+ PHI = this.inertiaX;
569
+ this.inertiaX *= 0.95;
570
+ this.inertiaY *= 0.95;
571
+ this._camera.rotate(PHI, THETA);
572
+ this._perspectiveMatrixManager.computePerspectiveMatrix(canvas, this._camera, bootSetup.camera_fov_deg, bootSetup.camera_near_plane, global.insideSphere);
573
+ }
574
+ else {
575
+ this.inertiaY = 0;
576
+ this.inertiaX = 0;
577
+ }
578
+ // Se la camera è ruotata (anche solo per inerzia), aggiorna punto centrale + emetti cameraChanged
579
+ if (cameraRotated) {
580
+ // Ricalcola il punto centrale
581
+ const center = this.updateCentralPoint();
582
+ const centralRaDeg = center.astroDeg.ra;
583
+ const centralDecDeg = center.astroDeg.dec;
584
+ // Evita spam: emetti solo se è cambiato abbastanza
585
+ const raChanged = this.prevCentralRaDeg === null ||
586
+ Math.abs(centralRaDeg - this.prevCentralRaDeg) > 1e-5;
587
+ const decChanged = this.prevCentralDecDeg === null ||
588
+ Math.abs(centralDecDeg - this.prevCentralDecDeg) > 1e-5;
589
+ if (raChanged || decChanged) {
590
+ this.prevCentralRaDeg = centralRaDeg;
591
+ this.prevCentralDecDeg = centralDecDeg;
592
+ }
593
+ }
594
+ if (this._cameraStatusChanged) {
595
+ const detail = this.getCurrentStatus();
596
+ if (detail) {
597
+ // console.log('[AstroSphere::draw] emitting camera-changed event due to camera status change', detail)
598
+ // console.log('[AstroSphere::draw] inertia', this.zoomInertia, this.inertiaX, this.inertiaY)
599
+ this.canvas.dispatchEvent(new CustomEvent('camera-changed', {
600
+ detail,
601
+ bubbles: true, composed: true,
602
+ }));
603
+ }
604
+ if (!this.startup) {
605
+ this._cameraStatusChanged = false;
606
+ }
607
+ }
608
+ // GL state
609
+ this._webgl.disable(this._webgl.DEPTH_TEST);
610
+ this._webgl.enable(this._webgl.BLEND);
611
+ this._webgl.enable(this._webgl.CULL_FACE);
612
+ this._webgl.cullFace(global.insideSphere ? this._webgl.BACK : this._webgl.FRONT);
613
+ this._webgl.blendFunc(this._webgl.SRC_ALPHA, this._webgl.ONE_MINUS_SRC_ALPHA);
614
+ const visibleOrder = Math.min(this._healpixGrid.visibleorder, this._activeHiPS.maxOrder);
615
+ this._healpixGrid.visibleTilesManager.computeVisiblePixels(visibleOrder, this._webgl, this._camera, this._perspectiveMatrixManager.pMatrix);
616
+ // DRAW HiPS
617
+ const skyEntityDrawInput = {
618
+ fovDeg: this._healpixGrid.getMinFoV(),
619
+ camera: this._camera,
620
+ pMatrix: this._perspectiveMatrixManager.pMatrix
621
+ };
622
+ this._activeHiPS.draw(skyEntityDrawInput);
623
+ this._healpixGrid.draw(skyEntityDrawInput);
624
+ this._equatorialGrid.draw(skyEntityDrawInput);
625
+ this._webgl.enable(this._webgl.DEPTH_TEST);
626
+ this._webgl.disable(this._webgl.CULL_FACE);
627
+ if (this.startup) {
628
+ this.startup = false;
629
+ const phiTheta = this.getPhiThetaDeg(canvas);
630
+ const raDecDeg = sphericalToAstroDeg(phiTheta.phi, phiTheta.theta);
631
+ const raHMS = raDegToHMS(raDecDeg.ra);
632
+ const decDMS = decDegToDMS(raDecDeg.dec);
633
+ this.prevFov = this._healpixGrid.getMinFoV();
634
+ this._cameraStatusChanged = true;
635
+ console.log('(startup coords)', {
636
+ raDeg: raDecDeg.ra,
637
+ decDeg: raDecDeg.dec,
638
+ raHMS,
639
+ decDMS,
640
+ });
641
+ }
642
+ this.activeCatalogues.forEach(cat => {
643
+ if (this._activeHiPS) {
644
+ cat.draw(this._activeHiPS.getModelMatrix(), this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
645
+ }
646
+ });
647
+ this.emitHoveredSourceIfChanged();
648
+ this.activeFootprintSets.forEach(fst => {
649
+ if (this._activeHiPS) {
650
+ fst.draw(this._activeHiPS.getModelMatrix(), this.mouseHelper, this._camera.getCameraMatrix(), this._perspectiveMatrixManager.pMatrix);
651
+ }
652
+ });
653
+ }
654
+ emitHoveredSourceIfChanged() {
655
+ let nextHoveredSource = null;
656
+ let nextHoveredCatalogue = null;
657
+ for (const cat of this.activeCatalogues) {
658
+ const hovered = cat.getPrimaryHoveredSource();
659
+ if (!hovered)
660
+ continue;
661
+ nextHoveredSource = hovered;
662
+ nextHoveredCatalogue = cat;
663
+ break;
664
+ }
665
+ const unchanged = nextHoveredSource === this.lastHoveredSource
666
+ && nextHoveredCatalogue === this.lastHoveredCatalogue;
667
+ if (unchanged)
668
+ return;
669
+ this.lastHoveredSource = nextHoveredSource;
670
+ this.lastHoveredCatalogue = nextHoveredCatalogue;
671
+ this._webgl.canvas.dispatchEvent(new CustomEvent('source-hovered', {
672
+ detail: { source: nextHoveredSource, catalogue: nextHoveredCatalogue },
673
+ bubbles: true,
674
+ composed: true,
675
+ }));
676
+ }
677
+ }
678
+ export default AstroSphere;
679
+ //# sourceMappingURL=AstroSphere.js.map