astro-viewer 3.10.0 → 3.11.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.
- package/README.md +66 -4
- package/dist/astroviewer.cjs +353 -8
- package/dist/astroviewer.cjs.map +1 -1
- package/dist/astroviewer.js +353 -8
- package/dist/astroviewer.js.map +1 -1
- package/dist/astroviewer.min.js +1 -1
- package/dist/astroviewer.min.js.map +1 -1
- package/lib-esm/AstroSphere.d.ts +1 -0
- package/lib-esm/AstroSphere.d.ts.map +1 -1
- package/lib-esm/AstroSphere.js +15 -0
- package/lib-esm/AstroSphere.js.map +1 -1
- package/lib-esm/AstroViewer.d.ts +1 -0
- package/lib-esm/AstroViewer.d.ts.map +1 -1
- package/lib-esm/AstroViewer.js +3 -0
- package/lib-esm/AstroViewer.js.map +1 -1
- package/lib-esm/Camera.d.ts +6 -0
- package/lib-esm/Camera.d.ts.map +1 -1
- package/lib-esm/Camera.js +102 -8
- package/lib-esm/Camera.js.map +1 -1
- package/lib-esm/model/Source.d.ts +11 -0
- package/lib-esm/model/Source.d.ts.map +1 -1
- package/lib-esm/model/Source.js +7 -0
- package/lib-esm/model/Source.js.map +1 -1
- package/lib-esm/model/catalogues/CatalogueGL.d.ts +23 -1
- package/lib-esm/model/catalogues/CatalogueGL.d.ts.map +1 -1
- package/lib-esm/model/catalogues/CatalogueGL.js +223 -1
- package/lib-esm/model/catalogues/CatalogueGL.js.map +1 -1
- package/package.json +1 -1
package/dist/astroviewer.js
CHANGED
|
@@ -53,6 +53,7 @@ __webpack_require__.d(vec3_namespaceObject, {
|
|
|
53
53
|
dot: () => (dot),
|
|
54
54
|
fromValues: () => (vec3_fromValues),
|
|
55
55
|
length: () => (vec3_length),
|
|
56
|
+
lerp: () => (lerp),
|
|
56
57
|
normalize: () => (normalize),
|
|
57
58
|
scale: () => (vec3_scale),
|
|
58
59
|
scaleAndAdd: () => (scaleAndAdd),
|
|
@@ -3906,6 +3907,7 @@ class AstroSphere {
|
|
|
3906
3907
|
const handleMouseDown = (event) => {
|
|
3907
3908
|
canvas.setPointerCapture(event.pointerId);
|
|
3908
3909
|
this.mouseDown = true;
|
|
3910
|
+
this._camera.cancelFlyTo();
|
|
3909
3911
|
const rect = canvas.getBoundingClientRect();
|
|
3910
3912
|
this.lastMouseX = event.clientX - rect.left; // locale al canvas
|
|
3911
3913
|
this.lastMouseY = event.clientY - rect.top; // locale al canvas
|
|
@@ -4032,6 +4034,7 @@ class AstroSphere {
|
|
|
4032
4034
|
const handleMouseWheel = (event) => {
|
|
4033
4035
|
const currentFov = this._healpixGrid.getMinFoV();
|
|
4034
4036
|
const zoomStep = this.computeZoomStep(currentFov, event.deltaY);
|
|
4037
|
+
this._camera.cancelFlyTo();
|
|
4035
4038
|
// Apply wheel zoom immediately and discard any queued inertia so reversing
|
|
4036
4039
|
// direction feels responsive instead of "buffered".
|
|
4037
4040
|
this.zoomInertia = 0;
|
|
@@ -4297,6 +4300,9 @@ class AstroSphere {
|
|
|
4297
4300
|
goTo(raDeg, decDeg) {
|
|
4298
4301
|
this._camera.goTo(raDeg, decDeg);
|
|
4299
4302
|
}
|
|
4303
|
+
flyTo(raDeg, decDeg, durationMs = 1200) {
|
|
4304
|
+
this._camera.flyTo(raDeg, decDeg, durationMs);
|
|
4305
|
+
}
|
|
4300
4306
|
getActiveCoordinateMode() {
|
|
4301
4307
|
if (this._activeBaseLayer === "xyz") {
|
|
4302
4308
|
return "lonlat";
|
|
@@ -4532,6 +4538,16 @@ class AstroSphere {
|
|
|
4532
4538
|
let PHI = 0;
|
|
4533
4539
|
this._webgl.viewport(0, 0, this._webgl.drawingBufferWidth, this._webgl.drawingBufferHeight);
|
|
4534
4540
|
this._webgl.clear(this._webgl.COLOR_BUFFER_BIT | this._webgl.DEPTH_BUFFER_BIT);
|
|
4541
|
+
const now = performance.now();
|
|
4542
|
+
const cameraFlying = this._camera.updateFlyTo(now);
|
|
4543
|
+
if (cameraFlying) {
|
|
4544
|
+
this.inertiaX = 0;
|
|
4545
|
+
this.inertiaY = 0;
|
|
4546
|
+
this.lastCameraMotionAt = now;
|
|
4547
|
+
this._cameraStatusChanged = true;
|
|
4548
|
+
this.updateCentralPoint();
|
|
4549
|
+
this._perspectiveMatrixManager.computePerspectiveMatrix(canvas, this._camera, Config_js_1.bootSetup.camera_fov_deg, Config_js_1.bootSetup.camera_near_plane, Global_js_1.default.insideSphere);
|
|
4550
|
+
}
|
|
4535
4551
|
// Zoom inertia
|
|
4536
4552
|
if (this.zoomInertia !== 0) {
|
|
4537
4553
|
if (Math.abs(this.zoomInertia) > 0.0001) {
|
|
@@ -5063,6 +5079,9 @@ class AstroViewer {
|
|
|
5063
5079
|
// console.log(`AstroViewer.goTo goto(${raDeg}, ${decDeg})`)
|
|
5064
5080
|
this.astroSphere.goTo(raDeg, decDeg);
|
|
5065
5081
|
}
|
|
5082
|
+
flyTo(raDeg, decDeg, durationMs = 1200) {
|
|
5083
|
+
this.astroSphere.flyTo(raDeg, decDeg, durationMs);
|
|
5084
|
+
}
|
|
5066
5085
|
getActiveCoordinateMode() {
|
|
5067
5086
|
return this.astroSphere.getActiveCoordinateMode();
|
|
5068
5087
|
}
|
|
@@ -5385,6 +5404,7 @@ class Camera {
|
|
|
5385
5404
|
lockRotX = false;
|
|
5386
5405
|
lockRotY = false;
|
|
5387
5406
|
lockRotZ = false;
|
|
5407
|
+
flyToAnimation = null;
|
|
5388
5408
|
constructor(in_position, in_sphere) {
|
|
5389
5409
|
this.init(in_position, in_sphere);
|
|
5390
5410
|
}
|
|
@@ -5394,7 +5414,11 @@ class Camera {
|
|
|
5394
5414
|
this.vMatrix = gl_matrix_1.mat4.create();
|
|
5395
5415
|
this.T = gl_matrix_1.mat4.create();
|
|
5396
5416
|
this.R = gl_matrix_1.mat4.create();
|
|
5397
|
-
gl_matrix_1.mat4.translate(this.T, this.T, [
|
|
5417
|
+
gl_matrix_1.mat4.translate(this.T, this.T, [
|
|
5418
|
+
this.cam_pos[0],
|
|
5419
|
+
this.cam_pos[1],
|
|
5420
|
+
this.cam_pos[2],
|
|
5421
|
+
]);
|
|
5398
5422
|
// reset helpers
|
|
5399
5423
|
this.FoV = this.previousFoV = 180.0;
|
|
5400
5424
|
this.move = gl_matrix_1.vec3.clone([0, 0, 0]);
|
|
@@ -5403,11 +5427,15 @@ class Camera {
|
|
|
5403
5427
|
this.goTo(raDeg, decDeg);
|
|
5404
5428
|
}
|
|
5405
5429
|
goTo(raDeg, decDeg) {
|
|
5430
|
+
this.cancelFlyTo();
|
|
5406
5431
|
this.goToPhiTheta((0, Utils_js_1.astroDegToSpherical)(raDeg, decDeg));
|
|
5407
5432
|
}
|
|
5408
5433
|
goToPhiTheta(ptDeg) {
|
|
5409
5434
|
const xyz = (0, Utils_js_1.sphericalToCartesian)(ptDeg.phi, ptDeg.theta, this.cam_pos[2]);
|
|
5410
|
-
|
|
5435
|
+
this.applyCameraPosition(gl_matrix_1.vec3.fromValues(xyz[0], xyz[1], xyz[2]));
|
|
5436
|
+
}
|
|
5437
|
+
applyCameraPosition(cameraPosition) {
|
|
5438
|
+
const targetDirection = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), cameraPosition);
|
|
5411
5439
|
const celestialNorth = gl_matrix_1.vec3.fromValues(0.0, 0.0, 1.0);
|
|
5412
5440
|
const northProjection = gl_matrix_1.vec3.scale(gl_matrix_1.vec3.create(), targetDirection, gl_matrix_1.vec3.dot(celestialNorth, targetDirection));
|
|
5413
5441
|
const cameraUp = gl_matrix_1.vec3.subtract(gl_matrix_1.vec3.create(), celestialNorth, northProjection);
|
|
@@ -5418,9 +5446,13 @@ class Camera {
|
|
|
5418
5446
|
gl_matrix_1.vec3.normalize(cameraUp, cameraUp);
|
|
5419
5447
|
}
|
|
5420
5448
|
let cameraMatrix = gl_matrix_1.mat4.create();
|
|
5421
|
-
cameraMatrix = gl_matrix_1.mat4.translate(cameraMatrix, cameraMatrix,
|
|
5449
|
+
cameraMatrix = gl_matrix_1.mat4.translate(cameraMatrix, cameraMatrix, cameraPosition);
|
|
5422
5450
|
const focusPoint = [0.0, 0.0, 0.0];
|
|
5423
|
-
const cameraPos = [
|
|
5451
|
+
const cameraPos = [
|
|
5452
|
+
cameraMatrix[12],
|
|
5453
|
+
cameraMatrix[13],
|
|
5454
|
+
cameraMatrix[14],
|
|
5455
|
+
];
|
|
5424
5456
|
cameraMatrix = gl_matrix_1.mat4.targetTo(cameraMatrix, cameraPos, focusPoint, cameraUp);
|
|
5425
5457
|
this.R = gl_matrix_1.mat4.clone(cameraMatrix);
|
|
5426
5458
|
this.R[12] = 0;
|
|
@@ -5432,6 +5464,81 @@ class Camera {
|
|
|
5432
5464
|
}
|
|
5433
5465
|
this.vMatrix = viewMatrix;
|
|
5434
5466
|
}
|
|
5467
|
+
flyTo(raDeg, decDeg, durationMs = 1200) {
|
|
5468
|
+
const targetSpherical = (0, Utils_js_1.astroDegToSpherical)(raDeg, decDeg);
|
|
5469
|
+
const targetPositionValues = (0, Utils_js_1.sphericalToCartesian)(targetSpherical.phi, targetSpherical.theta, this.cam_pos[2]);
|
|
5470
|
+
const targetPosition = gl_matrix_1.vec3.fromValues(targetPositionValues[0], targetPositionValues[1], targetPositionValues[2]);
|
|
5471
|
+
const currentPosition = this.getCameraPosition();
|
|
5472
|
+
const startDirection = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), gl_matrix_1.vec3.fromValues(currentPosition[0], currentPosition[1], currentPosition[2]));
|
|
5473
|
+
const targetDirection = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), targetPosition);
|
|
5474
|
+
this.flyToAnimation = {
|
|
5475
|
+
startDirection,
|
|
5476
|
+
targetDirection,
|
|
5477
|
+
targetPosition,
|
|
5478
|
+
startTime: performance.now(),
|
|
5479
|
+
durationMs: Math.max(1, durationMs),
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5482
|
+
updateFlyTo(now) {
|
|
5483
|
+
const animation = this.flyToAnimation;
|
|
5484
|
+
if (!animation) {
|
|
5485
|
+
return false;
|
|
5486
|
+
}
|
|
5487
|
+
const elapsed = now - animation.startTime;
|
|
5488
|
+
const progress = Math.min(1, elapsed / animation.durationMs);
|
|
5489
|
+
const easedProgress = progress < 0.5
|
|
5490
|
+
? 4 * progress * progress * progress
|
|
5491
|
+
: 1 - Math.pow(-2 * progress + 2, 3) / 2;
|
|
5492
|
+
const direction = this.slerpDirection(animation.startDirection, animation.targetDirection, easedProgress);
|
|
5493
|
+
const radius = Math.abs(this.cam_pos[2]);
|
|
5494
|
+
const cameraPosition = gl_matrix_1.vec3.scale(gl_matrix_1.vec3.create(), direction, radius);
|
|
5495
|
+
this.applyCameraPosition(cameraPosition);
|
|
5496
|
+
if (progress >= 1) {
|
|
5497
|
+
this.applyCameraPosition(animation.targetPosition);
|
|
5498
|
+
this.flyToAnimation = null;
|
|
5499
|
+
}
|
|
5500
|
+
return true;
|
|
5501
|
+
}
|
|
5502
|
+
slerpDirection(start, end, t) {
|
|
5503
|
+
const dot = Math.max(-1, Math.min(1, gl_matrix_1.vec3.dot(start, end)));
|
|
5504
|
+
/*
|
|
5505
|
+
* For almost identical directions, normalized linear interpolation is
|
|
5506
|
+
* numerically more stable than the general SLERP formula.
|
|
5507
|
+
*/
|
|
5508
|
+
if (dot > 0.999999) {
|
|
5509
|
+
const result = gl_matrix_1.vec3.lerp(gl_matrix_1.vec3.create(), start, end, t);
|
|
5510
|
+
return gl_matrix_1.vec3.normalize(result, result);
|
|
5511
|
+
}
|
|
5512
|
+
/*
|
|
5513
|
+
* The normal SLERP formula becomes singular for antipodal vectors because
|
|
5514
|
+
* sin(pi) = 0. In that case choose a stable vector orthogonal to start and
|
|
5515
|
+
* rotate through that great circle.
|
|
5516
|
+
*/
|
|
5517
|
+
if (dot < -0.999999) {
|
|
5518
|
+
const referenceAxis = Math.abs(start[0]) < 0.9
|
|
5519
|
+
? gl_matrix_1.vec3.fromValues(1, 0, 0)
|
|
5520
|
+
: gl_matrix_1.vec3.fromValues(0, 1, 0);
|
|
5521
|
+
const orthogonal = gl_matrix_1.vec3.cross(gl_matrix_1.vec3.create(), start, referenceAxis);
|
|
5522
|
+
gl_matrix_1.vec3.normalize(orthogonal, orthogonal);
|
|
5523
|
+
const angle = Math.PI * t;
|
|
5524
|
+
const result = gl_matrix_1.vec3.create();
|
|
5525
|
+
gl_matrix_1.vec3.scale(result, start, Math.cos(angle));
|
|
5526
|
+
gl_matrix_1.vec3.scaleAndAdd(result, result, orthogonal, Math.sin(angle));
|
|
5527
|
+
return gl_matrix_1.vec3.normalize(result, result);
|
|
5528
|
+
}
|
|
5529
|
+
const angle = Math.acos(dot);
|
|
5530
|
+
const sinAngle = Math.sin(angle);
|
|
5531
|
+
const startWeight = Math.sin((1 - t) * angle) / sinAngle;
|
|
5532
|
+
const endWeight = Math.sin(t * angle) / sinAngle;
|
|
5533
|
+
const result = gl_matrix_1.vec3.create();
|
|
5534
|
+
result[0] = start[0] * startWeight + end[0] * endWeight;
|
|
5535
|
+
result[1] = start[1] * startWeight + end[1] * endWeight;
|
|
5536
|
+
result[2] = start[2] * startWeight + end[2] * endWeight;
|
|
5537
|
+
return gl_matrix_1.vec3.normalize(result, result);
|
|
5538
|
+
}
|
|
5539
|
+
cancelFlyTo() {
|
|
5540
|
+
this.flyToAnimation = null;
|
|
5541
|
+
}
|
|
5435
5542
|
toggleInsideSphere() {
|
|
5436
5543
|
// if (inside !== global.insideSphere) {
|
|
5437
5544
|
// global.insideSphere = inside;
|
|
@@ -5689,9 +5796,15 @@ class Camera {
|
|
|
5689
5796
|
clearRotationLock() {
|
|
5690
5797
|
this.lockRotX = this.lockRotY = this.lockRotZ = false;
|
|
5691
5798
|
}
|
|
5692
|
-
isRotationLockedX() {
|
|
5693
|
-
|
|
5694
|
-
|
|
5799
|
+
isRotationLockedX() {
|
|
5800
|
+
return this.lockRotX;
|
|
5801
|
+
}
|
|
5802
|
+
isRotationLockedY() {
|
|
5803
|
+
return this.lockRotY;
|
|
5804
|
+
}
|
|
5805
|
+
isRotationLockedZ() {
|
|
5806
|
+
return this.lockRotZ;
|
|
5807
|
+
}
|
|
5695
5808
|
}
|
|
5696
5809
|
exports["default"] = Camera;
|
|
5697
5810
|
|
|
@@ -7903,6 +8016,7 @@ class Source {
|
|
|
7903
8016
|
_h_pix;
|
|
7904
8017
|
_shapesize;
|
|
7905
8018
|
_brightnessFactor;
|
|
8019
|
+
_mediaStyle;
|
|
7906
8020
|
/**
|
|
7907
8021
|
* @param in_point Point.js (Cartesian/RA-Dec wrapper)
|
|
7908
8022
|
* @param in_details Optional array of key/value metadata
|
|
@@ -7955,6 +8069,12 @@ class Source {
|
|
|
7955
8069
|
set brightnessFactor(factor) {
|
|
7956
8070
|
this._brightnessFactor = factor;
|
|
7957
8071
|
}
|
|
8072
|
+
get mediaStyle() {
|
|
8073
|
+
return this._mediaStyle;
|
|
8074
|
+
}
|
|
8075
|
+
set mediaStyle(style) {
|
|
8076
|
+
this._mediaStyle = style;
|
|
8077
|
+
}
|
|
7958
8078
|
}
|
|
7959
8079
|
exports.Source = Source;
|
|
7960
8080
|
|
|
@@ -8182,6 +8302,9 @@ exports.SphereFoV = SphereFoV;
|
|
|
8182
8302
|
*
|
|
8183
8303
|
* See LICENSE.md, LICENSE-AGPL.md, and LICENSE-COMMERCIAL.md for details.
|
|
8184
8304
|
*/
|
|
8305
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8306
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8307
|
+
};
|
|
8185
8308
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
8186
8309
|
exports.CatalogueGL = void 0;
|
|
8187
8310
|
const Source_js_1 = __webpack_require__(146);
|
|
@@ -8190,6 +8313,8 @@ const CoordsType_js_1 = __webpack_require__(8145);
|
|
|
8190
8313
|
const Utils_js_1 = __webpack_require__(7930);
|
|
8191
8314
|
const CatalogueShaderProgram_js_1 = __webpack_require__(3559);
|
|
8192
8315
|
const MetadataManager_js_1 = __webpack_require__(5403);
|
|
8316
|
+
const gl_matrix_1 = __webpack_require__(3890);
|
|
8317
|
+
const Global_js_1 = __importDefault(__webpack_require__(4382));
|
|
8193
8318
|
class CatalogueGL {
|
|
8194
8319
|
_kind = "CatalogueGL";
|
|
8195
8320
|
static ELEM_SIZE = 6;
|
|
@@ -8221,6 +8346,9 @@ class CatalogueGL {
|
|
|
8221
8346
|
_providerUrl;
|
|
8222
8347
|
_catalogueShaderProgram;
|
|
8223
8348
|
_visibleTilesManager;
|
|
8349
|
+
_mediaOverlayHost = null;
|
|
8350
|
+
_mediaElements = [];
|
|
8351
|
+
_svgMediaDataUrls = new Map();
|
|
8224
8352
|
constructor(catalogueName, catalogueDescription, providerUrl, metadataManager, webgl, visibleTilesManager) {
|
|
8225
8353
|
this._webgl = webgl;
|
|
8226
8354
|
this._ready = false;
|
|
@@ -8391,9 +8519,10 @@ class CatalogueGL {
|
|
|
8391
8519
|
* @param in_data Rows of TAP results
|
|
8392
8520
|
* @param columnsmeta TapMetadataList (unused here because `CatalogueProps` already holds indices)
|
|
8393
8521
|
*/
|
|
8394
|
-
addSources(in_data, columnsmeta) {
|
|
8522
|
+
addSources(in_data, columnsmeta, options = {}) {
|
|
8395
8523
|
this._ready = false;
|
|
8396
8524
|
this._sources = [];
|
|
8525
|
+
this.clearMediaOverlay();
|
|
8397
8526
|
this._metadataManager = new MetadataManager_js_1.MetadataManager(columnsmeta);
|
|
8398
8527
|
// const raDataIndex = (this.catalogueProps.raColumn as any).index ?? (this.catalogueProps.raColumn as any)._index;
|
|
8399
8528
|
// const decDataIndex = (this.catalogueProps.decColumn as any).index ?? (this.catalogueProps.decColumn as any)._index;
|
|
@@ -8407,6 +8536,10 @@ class CatalogueGL {
|
|
|
8407
8536
|
decDeg: in_data[j][decDataIndex],
|
|
8408
8537
|
}, CoordsType_js_1.CoordsType.ASTRO);
|
|
8409
8538
|
const source = new Source_js_1.Source(point, in_data[j]);
|
|
8539
|
+
const mediaStyle = this.extractMediaStyle(in_data[j], columnsmeta, options.mediaColumns);
|
|
8540
|
+
if (mediaStyle) {
|
|
8541
|
+
source.mediaStyle = mediaStyle;
|
|
8542
|
+
}
|
|
8410
8543
|
// Ensure optional fields exist
|
|
8411
8544
|
source.shapeSize = source.shapeSize ?? CatalogueGL.STANDARD_SHAPE_SIZE;
|
|
8412
8545
|
source.brightnessFactor = 3;
|
|
@@ -8426,11 +8559,222 @@ class CatalogueGL {
|
|
|
8426
8559
|
this._ready = true;
|
|
8427
8560
|
this._bufferInitialised = false;
|
|
8428
8561
|
}
|
|
8562
|
+
getColumnIndex(columnsmeta, columnName) {
|
|
8563
|
+
if (!columnName)
|
|
8564
|
+
return -1;
|
|
8565
|
+
return columnsmeta.find((column) => column.name === columnName)?.index ?? -1;
|
|
8566
|
+
}
|
|
8567
|
+
readCell(row, columnsmeta, columnName) {
|
|
8568
|
+
const idx = this.getColumnIndex(columnsmeta, columnName);
|
|
8569
|
+
return idx >= 0 ? row[idx] : undefined;
|
|
8570
|
+
}
|
|
8571
|
+
extractMediaStyle(row, columnsmeta, mediaColumns) {
|
|
8572
|
+
if (!mediaColumns?.src)
|
|
8573
|
+
return undefined;
|
|
8574
|
+
const rawSrc = this.readCell(row, columnsmeta, mediaColumns.src);
|
|
8575
|
+
const src = String(rawSrc ?? "").trim();
|
|
8576
|
+
if (!src)
|
|
8577
|
+
return undefined;
|
|
8578
|
+
const rawKind = String(this.readCell(row, columnsmeta, mediaColumns.type) ?? "sprite").trim().toLowerCase();
|
|
8579
|
+
const kind = rawKind === "model"
|
|
8580
|
+
? "model"
|
|
8581
|
+
: rawKind === "image"
|
|
8582
|
+
? "image"
|
|
8583
|
+
: rawKind === "icon"
|
|
8584
|
+
? "icon"
|
|
8585
|
+
: rawKind === "circle"
|
|
8586
|
+
? "circle"
|
|
8587
|
+
: "sprite";
|
|
8588
|
+
if (kind === "circle" || kind === "model")
|
|
8589
|
+
return undefined;
|
|
8590
|
+
const scale = Number(this.readCell(row, columnsmeta, mediaColumns.scale));
|
|
8591
|
+
const rotationDeg = Number(this.readCell(row, columnsmeta, mediaColumns.rotation));
|
|
8592
|
+
const opacity = Number(this.readCell(row, columnsmeta, mediaColumns.opacity));
|
|
8593
|
+
return {
|
|
8594
|
+
kind,
|
|
8595
|
+
src,
|
|
8596
|
+
scale: Number.isFinite(scale) && scale > 0 ? scale : undefined,
|
|
8597
|
+
rotationDeg: Number.isFinite(rotationDeg) ? rotationDeg : undefined,
|
|
8598
|
+
opacity: Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : undefined,
|
|
8599
|
+
};
|
|
8600
|
+
}
|
|
8429
8601
|
clearSources() {
|
|
8430
8602
|
this._sources = [];
|
|
8431
8603
|
this.hoveredIndexes = [];
|
|
8432
8604
|
this._healpixDensityMap.clear();
|
|
8433
8605
|
this.vertexCataloguePosition = new Float32Array(0);
|
|
8606
|
+
this.clearMediaOverlay();
|
|
8607
|
+
}
|
|
8608
|
+
clearMediaOverlay() {
|
|
8609
|
+
this._mediaElements.forEach((el) => el.remove());
|
|
8610
|
+
this._mediaElements = [];
|
|
8611
|
+
if (this._mediaOverlayHost) {
|
|
8612
|
+
this._mediaOverlayHost.remove();
|
|
8613
|
+
this._mediaOverlayHost = null;
|
|
8614
|
+
}
|
|
8615
|
+
}
|
|
8616
|
+
ensureMediaOverlayHost() {
|
|
8617
|
+
const canvas = this._webgl?.canvas;
|
|
8618
|
+
const parent = canvas?.parentElement;
|
|
8619
|
+
if (!canvas || !parent)
|
|
8620
|
+
return null;
|
|
8621
|
+
const parentStyle = window.getComputedStyle(parent);
|
|
8622
|
+
if (parentStyle.position === "static") {
|
|
8623
|
+
parent.style.position = "relative";
|
|
8624
|
+
}
|
|
8625
|
+
if (!this._mediaOverlayHost) {
|
|
8626
|
+
const host = document.createElement("div");
|
|
8627
|
+
host.dataset.astroCatalogueMedia = "true";
|
|
8628
|
+
host.style.position = "absolute";
|
|
8629
|
+
host.style.left = `${canvas.offsetLeft}px`;
|
|
8630
|
+
host.style.top = `${canvas.offsetTop}px`;
|
|
8631
|
+
host.style.width = `${canvas.clientWidth}px`;
|
|
8632
|
+
host.style.height = `${canvas.clientHeight}px`;
|
|
8633
|
+
host.style.pointerEvents = "none";
|
|
8634
|
+
host.style.overflow = "hidden";
|
|
8635
|
+
host.style.zIndex = "4";
|
|
8636
|
+
canvas.style.position = canvas.style.position || "relative";
|
|
8637
|
+
canvas.style.zIndex = canvas.style.zIndex || "0";
|
|
8638
|
+
parent.appendChild(host);
|
|
8639
|
+
this._mediaOverlayHost = host;
|
|
8640
|
+
}
|
|
8641
|
+
else {
|
|
8642
|
+
this._mediaOverlayHost.style.left = `${canvas.offsetLeft}px`;
|
|
8643
|
+
this._mediaOverlayHost.style.top = `${canvas.offsetTop}px`;
|
|
8644
|
+
this._mediaOverlayHost.style.width = `${canvas.clientWidth}px`;
|
|
8645
|
+
this._mediaOverlayHost.style.height = `${canvas.clientHeight}px`;
|
|
8646
|
+
}
|
|
8647
|
+
return this._mediaOverlayHost;
|
|
8648
|
+
}
|
|
8649
|
+
ensureMediaElement(index, style) {
|
|
8650
|
+
let img = this._mediaElements[index];
|
|
8651
|
+
if (!img) {
|
|
8652
|
+
img = document.createElement("img");
|
|
8653
|
+
img.loading = "lazy";
|
|
8654
|
+
img.decoding = "async";
|
|
8655
|
+
img.style.position = "absolute";
|
|
8656
|
+
img.style.objectFit = "contain";
|
|
8657
|
+
img.style.pointerEvents = "none";
|
|
8658
|
+
img.style.transformOrigin = "center center";
|
|
8659
|
+
img.style.filter = "drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55))";
|
|
8660
|
+
img.style.willChange = "transform, left, top";
|
|
8661
|
+
this._mediaElements[index] = img;
|
|
8662
|
+
}
|
|
8663
|
+
const src = String(style.src ?? "").trim();
|
|
8664
|
+
const resolvedSrc = src ? new URL(src, document.baseURI).href : "";
|
|
8665
|
+
if (resolvedSrc && img.getAttribute("src") !== resolvedSrc) {
|
|
8666
|
+
img.removeAttribute("data-astro-media-src-index");
|
|
8667
|
+
img.removeAttribute("data-astro-media-loaded");
|
|
8668
|
+
img.onerror = null;
|
|
8669
|
+
img.onload = null;
|
|
8670
|
+
img.setAttribute("src", resolvedSrc);
|
|
8671
|
+
if (/\.svg(?:[?#].*)?$/i.test(resolvedSrc)) {
|
|
8672
|
+
void this.loadSvgMediaAsDataUrl(img, resolvedSrc);
|
|
8673
|
+
}
|
|
8674
|
+
}
|
|
8675
|
+
return img;
|
|
8676
|
+
}
|
|
8677
|
+
async loadSvgMediaAsDataUrl(img, resolvedSrc) {
|
|
8678
|
+
try {
|
|
8679
|
+
let dataUrl = this._svgMediaDataUrls.get(resolvedSrc);
|
|
8680
|
+
if (!dataUrl) {
|
|
8681
|
+
const response = await fetch(resolvedSrc);
|
|
8682
|
+
if (!response.ok)
|
|
8683
|
+
return;
|
|
8684
|
+
const svg = await response.text();
|
|
8685
|
+
if (!/^\s*<svg[\s>]/i.test(svg))
|
|
8686
|
+
return;
|
|
8687
|
+
dataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
8688
|
+
this._svgMediaDataUrls.set(resolvedSrc, dataUrl);
|
|
8689
|
+
}
|
|
8690
|
+
if (img.getAttribute("src") === resolvedSrc) {
|
|
8691
|
+
img.setAttribute("src", dataUrl);
|
|
8692
|
+
}
|
|
8693
|
+
}
|
|
8694
|
+
catch {
|
|
8695
|
+
// Keep the direct image src; remote servers may already provide a valid MIME type.
|
|
8696
|
+
}
|
|
8697
|
+
}
|
|
8698
|
+
isSourceOnVisibleHemisphere(source, in_mMatrix, vMatrix) {
|
|
8699
|
+
if (Global_js_1.default.insideSphere)
|
|
8700
|
+
return true;
|
|
8701
|
+
const invView = gl_matrix_1.mat4.create();
|
|
8702
|
+
if (!gl_matrix_1.mat4.invert(invView, vMatrix))
|
|
8703
|
+
return true;
|
|
8704
|
+
const cameraPos = gl_matrix_1.vec3.fromValues(invView[12], invView[13], invView[14]);
|
|
8705
|
+
const worldPoint4 = gl_matrix_1.vec4.fromValues(source.point.x, source.point.y, source.point.z, 1);
|
|
8706
|
+
gl_matrix_1.vec4.transformMat4(worldPoint4, worldPoint4, in_mMatrix);
|
|
8707
|
+
const worldPoint = gl_matrix_1.vec3.fromValues(worldPoint4[0], worldPoint4[1], worldPoint4[2]);
|
|
8708
|
+
const normal = gl_matrix_1.vec3.normalize(gl_matrix_1.vec3.create(), worldPoint);
|
|
8709
|
+
const toCamera = gl_matrix_1.vec3.subtract(gl_matrix_1.vec3.create(), cameraPos, worldPoint);
|
|
8710
|
+
return gl_matrix_1.vec3.dot(normal, toCamera) > 0;
|
|
8711
|
+
}
|
|
8712
|
+
updateMediaOverlay(in_mMatrix, vMatrix, pMatrix) {
|
|
8713
|
+
const sourcesWithMedia = this._sources.filter((source) => !!source.mediaStyle?.src);
|
|
8714
|
+
if (!sourcesWithMedia.length) {
|
|
8715
|
+
this.clearMediaOverlay();
|
|
8716
|
+
return;
|
|
8717
|
+
}
|
|
8718
|
+
const host = this.ensureMediaOverlayHost();
|
|
8719
|
+
const canvas = this._webgl.canvas;
|
|
8720
|
+
if (!host || !canvas.clientWidth || !canvas.clientHeight)
|
|
8721
|
+
return;
|
|
8722
|
+
const modelView = gl_matrix_1.mat4.create();
|
|
8723
|
+
const mvp = gl_matrix_1.mat4.create();
|
|
8724
|
+
gl_matrix_1.mat4.multiply(modelView, vMatrix, in_mMatrix);
|
|
8725
|
+
gl_matrix_1.mat4.multiply(mvp, pMatrix, modelView);
|
|
8726
|
+
const width = canvas.clientWidth;
|
|
8727
|
+
const height = canvas.clientHeight;
|
|
8728
|
+
for (let i = 0; i < this._sources.length; i++) {
|
|
8729
|
+
const source = this._sources[i];
|
|
8730
|
+
const style = source.mediaStyle;
|
|
8731
|
+
const img = this._mediaElements[i];
|
|
8732
|
+
if (!style?.src) {
|
|
8733
|
+
if (img)
|
|
8734
|
+
img.style.display = "none";
|
|
8735
|
+
continue;
|
|
8736
|
+
}
|
|
8737
|
+
if (!this.isSourceOnVisibleHemisphere(source, in_mMatrix, vMatrix)) {
|
|
8738
|
+
if (img)
|
|
8739
|
+
img.style.display = "none";
|
|
8740
|
+
continue;
|
|
8741
|
+
}
|
|
8742
|
+
const projected = gl_matrix_1.vec4.fromValues(source.point.x, source.point.y, source.point.z, 1);
|
|
8743
|
+
gl_matrix_1.vec4.transformMat4(projected, projected, mvp);
|
|
8744
|
+
if (!projected[3]) {
|
|
8745
|
+
if (img)
|
|
8746
|
+
img.style.display = "none";
|
|
8747
|
+
continue;
|
|
8748
|
+
}
|
|
8749
|
+
const ndcX = projected[0] / projected[3];
|
|
8750
|
+
const ndcY = projected[1] / projected[3];
|
|
8751
|
+
const ndcZ = projected[2] / projected[3];
|
|
8752
|
+
if (ndcX < -1.15 ||
|
|
8753
|
+
ndcX > 1.15 ||
|
|
8754
|
+
ndcY < -1.15 ||
|
|
8755
|
+
ndcY > 1.15 ||
|
|
8756
|
+
ndcZ < -1.15 ||
|
|
8757
|
+
ndcZ > 1.15) {
|
|
8758
|
+
if (img)
|
|
8759
|
+
img.style.display = "none";
|
|
8760
|
+
continue;
|
|
8761
|
+
}
|
|
8762
|
+
const mediaEl = this.ensureMediaElement(i, style);
|
|
8763
|
+
if (!mediaEl.parentElement)
|
|
8764
|
+
host.appendChild(mediaEl);
|
|
8765
|
+
const px = (ndcX * 0.5 + 0.5) * width;
|
|
8766
|
+
const py = (1 - (ndcY * 0.5 + 0.5)) * height;
|
|
8767
|
+
const baseSize = source.shapeSize || CatalogueGL.STANDARD_SHAPE_SIZE;
|
|
8768
|
+
const size = Math.max(8, baseSize * (style.scale ?? 2.4));
|
|
8769
|
+
const rotation = style.rotationDeg ?? 0;
|
|
8770
|
+
mediaEl.style.display = "block";
|
|
8771
|
+
mediaEl.style.left = `${px - size / 2}px`;
|
|
8772
|
+
mediaEl.style.top = `${py - size / 2}px`;
|
|
8773
|
+
mediaEl.style.width = `${size}px`;
|
|
8774
|
+
mediaEl.style.height = `${size}px`;
|
|
8775
|
+
mediaEl.style.opacity = `${style.opacity ?? 1}`;
|
|
8776
|
+
mediaEl.style.transform = `rotate(${rotation}deg)`;
|
|
8777
|
+
}
|
|
8434
8778
|
}
|
|
8435
8779
|
sourceMatches(left, right) {
|
|
8436
8780
|
if (left === right)
|
|
@@ -8770,6 +9114,7 @@ class CatalogueGL {
|
|
|
8770
9114
|
// draw
|
|
8771
9115
|
const numItems = this.vertexCataloguePosition.length / CatalogueGL.ELEM_SIZE;
|
|
8772
9116
|
this._webgl.drawArrays(this._webgl.POINTS, 0, numItems);
|
|
9117
|
+
this.updateMediaOverlay(in_mMatrix, vMatrix, pMatrix);
|
|
8773
9118
|
this._oldMouseCoords = in_mouseHelper.xyz;
|
|
8774
9119
|
}
|
|
8775
9120
|
}
|