@project-skymap/library 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +267 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +267 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -103,6 +103,7 @@ type StarMapProps = {
|
|
|
103
103
|
onHover?: (node?: SceneNode) => void;
|
|
104
104
|
onArrangementChange?: (arrangement: StarArrangement) => void;
|
|
105
105
|
onFovChange?: (fov: number) => void;
|
|
106
|
+
onLongPress?: (node: SceneNode | null, x: number, y: number) => void;
|
|
106
107
|
};
|
|
107
108
|
type StarMapHandle = {
|
|
108
109
|
getFullArrangement: () => StarArrangement | undefined;
|
|
@@ -29243,7 +29244,7 @@ interface Projection {
|
|
|
29243
29244
|
*/
|
|
29244
29245
|
isClipped(dirZ: number): boolean;
|
|
29245
29246
|
}
|
|
29246
|
-
type ProjectionId = "perspective" | "stereographic"
|
|
29247
|
+
type ProjectionId = "perspective" | "stereographic";
|
|
29247
29248
|
declare const PROJECTIONS: Record<ProjectionId, () => Projection>;
|
|
29248
29249
|
|
|
29249
29250
|
export { type BibleJSON, type ConstellationConfig, type GenerateOptions, type HierarchyFilter, PROJECTIONS, type Projection, type ProjectionId, type SceneLink, type SceneModel, type SceneNode, type StarArrangement, StarMap, type StarMapConfig, type StarMapHandle, type StarMapProps, bibleToSceneModel, defaultGenerateOptions, defaultStars, generateArrangement };
|
package/dist/index.d.ts
CHANGED
|
@@ -103,6 +103,7 @@ type StarMapProps = {
|
|
|
103
103
|
onHover?: (node?: SceneNode) => void;
|
|
104
104
|
onArrangementChange?: (arrangement: StarArrangement) => void;
|
|
105
105
|
onFovChange?: (fov: number) => void;
|
|
106
|
+
onLongPress?: (node: SceneNode | null, x: number, y: number) => void;
|
|
106
107
|
};
|
|
107
108
|
type StarMapHandle = {
|
|
108
109
|
getFullArrangement: () => StarArrangement | undefined;
|
|
@@ -29243,7 +29244,7 @@ interface Projection {
|
|
|
29243
29244
|
*/
|
|
29244
29245
|
isClipped(dirZ: number): boolean;
|
|
29245
29246
|
}
|
|
29246
|
-
type ProjectionId = "perspective" | "stereographic"
|
|
29247
|
+
type ProjectionId = "perspective" | "stereographic";
|
|
29247
29248
|
declare const PROJECTIONS: Record<ProjectionId, () => Projection>;
|
|
29248
29249
|
|
|
29249
29250
|
export { type BibleJSON, type ConstellationConfig, type GenerateOptions, type HierarchyFilter, PROJECTIONS, type Projection, type ProjectionId, type SceneLink, type SceneModel, type SceneNode, type StarArrangement, StarMap, type StarMapConfig, type StarMapHandle, type StarMapProps, bibleToSceneModel, defaultGenerateOptions, defaultStars, generateArrangement };
|
package/dist/index.js
CHANGED
|
@@ -724,10 +724,14 @@ var init_projections = __esm({
|
|
|
724
724
|
maxFov = 165;
|
|
725
725
|
glslProjectionType = 2;
|
|
726
726
|
/** FOV thresholds for blend transition (degrees) */
|
|
727
|
-
blendStart
|
|
728
|
-
blendEnd
|
|
727
|
+
blendStart;
|
|
728
|
+
blendEnd;
|
|
729
729
|
/** Current blend factor, updated via setFov() */
|
|
730
730
|
blend = 0;
|
|
731
|
+
constructor(blendStart = 40, blendEnd = 100) {
|
|
732
|
+
this.blendStart = blendStart;
|
|
733
|
+
this.blendEnd = blendEnd;
|
|
734
|
+
}
|
|
731
735
|
/** Call this each frame / when FOV changes so forward/inverse stay in sync */
|
|
732
736
|
setFov(fovDeg) {
|
|
733
737
|
if (fovDeg <= this.blendStart) {
|
|
@@ -780,8 +784,7 @@ var init_projections = __esm({
|
|
|
780
784
|
};
|
|
781
785
|
PROJECTIONS = {
|
|
782
786
|
perspective: () => new PerspectiveProjection(),
|
|
783
|
-
stereographic: () => new StereographicProjection()
|
|
784
|
-
blended: () => new BlendedProjection()
|
|
787
|
+
stereographic: () => new StereographicProjection()
|
|
785
788
|
};
|
|
786
789
|
}
|
|
787
790
|
});
|
|
@@ -824,7 +827,8 @@ function createEngine({
|
|
|
824
827
|
onSelect,
|
|
825
828
|
onHover,
|
|
826
829
|
onArrangementChange,
|
|
827
|
-
onFovChange
|
|
830
|
+
onFovChange,
|
|
831
|
+
onLongPress
|
|
828
832
|
}) {
|
|
829
833
|
let hoveredBookId = null;
|
|
830
834
|
let focusedBookId = null;
|
|
@@ -884,18 +888,36 @@ function createEngine({
|
|
|
884
888
|
draggedStarIndex: -1,
|
|
885
889
|
draggedDist: 2e3,
|
|
886
890
|
draggedGroup: null,
|
|
887
|
-
tempArrangement: {}
|
|
891
|
+
tempArrangement: {},
|
|
892
|
+
// Touch state
|
|
893
|
+
touchCount: 0,
|
|
894
|
+
touchStartTime: 0,
|
|
895
|
+
touchStartX: 0,
|
|
896
|
+
touchStartY: 0,
|
|
897
|
+
touchMoved: false,
|
|
898
|
+
pinchStartDistance: 0,
|
|
899
|
+
pinchStartFov: ENGINE_CONFIG.defaultFov,
|
|
900
|
+
pinchCenterX: 0,
|
|
901
|
+
pinchCenterY: 0,
|
|
902
|
+
// Double-tap detection
|
|
903
|
+
lastTapTime: 0,
|
|
904
|
+
lastTapX: 0,
|
|
905
|
+
lastTapY: 0,
|
|
906
|
+
// Long-press detection
|
|
907
|
+
longPressTimer: null,
|
|
908
|
+
longPressTriggered: false
|
|
888
909
|
};
|
|
889
910
|
const mouseNDC = new THREE5.Vector2();
|
|
890
911
|
let isMouseInWindow = false;
|
|
912
|
+
let isTouchDevice = false;
|
|
891
913
|
let edgeHoverStart = 0;
|
|
892
|
-
let handlers = { onSelect, onHover, onArrangementChange, onFovChange };
|
|
914
|
+
let handlers = { onSelect, onHover, onArrangementChange, onFovChange, onLongPress };
|
|
893
915
|
let currentConfig;
|
|
894
916
|
const constellationLayer = new ConstellationArtworkLayer(scene);
|
|
895
917
|
function mix(a, b, t) {
|
|
896
918
|
return a * (1 - t) + b * t;
|
|
897
919
|
}
|
|
898
|
-
let currentProjection =
|
|
920
|
+
let currentProjection = new BlendedProjection(ENGINE_CONFIG.blendStart, ENGINE_CONFIG.blendEnd);
|
|
899
921
|
function syncProjectionState() {
|
|
900
922
|
if (currentProjection instanceof BlendedProjection) {
|
|
901
923
|
currentProjection.setFov(state.fov);
|
|
@@ -1933,9 +1955,13 @@ function createEngine({
|
|
|
1933
1955
|
let lastAppliedLat = void 0;
|
|
1934
1956
|
let lastBackdropCount = void 0;
|
|
1935
1957
|
function setProjection(id) {
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1958
|
+
if (id === "blended") {
|
|
1959
|
+
currentProjection = new BlendedProjection(ENGINE_CONFIG.blendStart, ENGINE_CONFIG.blendEnd);
|
|
1960
|
+
} else {
|
|
1961
|
+
const factory = PROJECTIONS[id];
|
|
1962
|
+
if (!factory) return;
|
|
1963
|
+
currentProjection = factory();
|
|
1964
|
+
}
|
|
1939
1965
|
updateUniforms();
|
|
1940
1966
|
}
|
|
1941
1967
|
function setConfig(cfg) {
|
|
@@ -2050,7 +2076,8 @@ function createEngine({
|
|
|
2050
2076
|
const w = rect.width;
|
|
2051
2077
|
const h = rect.height;
|
|
2052
2078
|
let closestLabel = null;
|
|
2053
|
-
|
|
2079
|
+
const LABEL_THRESHOLD = isTouchDevice ? 48 : 40;
|
|
2080
|
+
let minLabelDist = LABEL_THRESHOLD;
|
|
2054
2081
|
for (const item of dynamicLabels) {
|
|
2055
2082
|
if (!item.obj.visible) continue;
|
|
2056
2083
|
if (isNodeFiltered(item.node)) continue;
|
|
@@ -2363,6 +2390,196 @@ function createEngine({
|
|
|
2363
2390
|
state.targetLat = state.lat;
|
|
2364
2391
|
state.targetLon = state.lon;
|
|
2365
2392
|
}
|
|
2393
|
+
function getTouchDistance(t1, t2) {
|
|
2394
|
+
const dx = t1.clientX - t2.clientX;
|
|
2395
|
+
const dy = t1.clientY - t2.clientY;
|
|
2396
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
2397
|
+
}
|
|
2398
|
+
function getTouchCenter(t1, t2) {
|
|
2399
|
+
return {
|
|
2400
|
+
x: (t1.clientX + t2.clientX) / 2,
|
|
2401
|
+
y: (t1.clientY + t2.clientY) / 2
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
function onTouchStart(e) {
|
|
2405
|
+
e.preventDefault();
|
|
2406
|
+
isTouchDevice = true;
|
|
2407
|
+
if (state.longPressTimer) {
|
|
2408
|
+
clearTimeout(state.longPressTimer);
|
|
2409
|
+
state.longPressTimer = null;
|
|
2410
|
+
}
|
|
2411
|
+
state.longPressTriggered = false;
|
|
2412
|
+
const touches = e.touches;
|
|
2413
|
+
state.touchCount = touches.length;
|
|
2414
|
+
if (touches.length === 1) {
|
|
2415
|
+
const touch = touches[0];
|
|
2416
|
+
state.touchStartTime = performance.now();
|
|
2417
|
+
state.touchStartX = touch.clientX;
|
|
2418
|
+
state.touchStartY = touch.clientY;
|
|
2419
|
+
state.touchMoved = false;
|
|
2420
|
+
state.lastMouseX = touch.clientX;
|
|
2421
|
+
state.lastMouseY = touch.clientY;
|
|
2422
|
+
flyToActive = false;
|
|
2423
|
+
state.dragMode = "camera";
|
|
2424
|
+
state.isDragging = true;
|
|
2425
|
+
state.velocityX = 0;
|
|
2426
|
+
state.velocityY = 0;
|
|
2427
|
+
state.longPressTimer = setTimeout(() => {
|
|
2428
|
+
if (!state.touchMoved && state.touchCount === 1) {
|
|
2429
|
+
state.longPressTriggered = true;
|
|
2430
|
+
const rect = renderer.domElement.getBoundingClientRect();
|
|
2431
|
+
const mX = state.touchStartX - rect.left;
|
|
2432
|
+
const mY = state.touchStartY - rect.top;
|
|
2433
|
+
mouseNDC.x = mX / rect.width * 2 - 1;
|
|
2434
|
+
mouseNDC.y = -(mY / rect.height) * 2 + 1;
|
|
2435
|
+
const syntheticEvent = {
|
|
2436
|
+
clientX: state.touchStartX,
|
|
2437
|
+
clientY: state.touchStartY
|
|
2438
|
+
};
|
|
2439
|
+
const hit = pick(syntheticEvent);
|
|
2440
|
+
handlers.onLongPress?.(hit?.node ?? null, state.touchStartX, state.touchStartY);
|
|
2441
|
+
}
|
|
2442
|
+
}, ENGINE_CONFIG.longPressDelay);
|
|
2443
|
+
} else if (touches.length === 2) {
|
|
2444
|
+
const t0 = touches[0];
|
|
2445
|
+
const t1 = touches[1];
|
|
2446
|
+
state.pinchStartDistance = getTouchDistance(t0, t1);
|
|
2447
|
+
state.pinchStartFov = state.fov;
|
|
2448
|
+
const center = getTouchCenter(t0, t1);
|
|
2449
|
+
state.pinchCenterX = center.x;
|
|
2450
|
+
state.pinchCenterY = center.y;
|
|
2451
|
+
state.lastMouseX = center.x;
|
|
2452
|
+
state.lastMouseY = center.y;
|
|
2453
|
+
state.touchMoved = true;
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
function onTouchMove(e) {
|
|
2457
|
+
e.preventDefault();
|
|
2458
|
+
const touches = e.touches;
|
|
2459
|
+
if (touches.length === 1 && state.dragMode === "camera") {
|
|
2460
|
+
const touch = touches[0];
|
|
2461
|
+
const deltaX = touch.clientX - state.lastMouseX;
|
|
2462
|
+
const deltaY = touch.clientY - state.lastMouseY;
|
|
2463
|
+
state.lastMouseX = touch.clientX;
|
|
2464
|
+
state.lastMouseY = touch.clientY;
|
|
2465
|
+
const totalDx = touch.clientX - state.touchStartX;
|
|
2466
|
+
const totalDy = touch.clientY - state.touchStartY;
|
|
2467
|
+
if (Math.sqrt(totalDx * totalDx + totalDy * totalDy) > ENGINE_CONFIG.tapMaxDistance) {
|
|
2468
|
+
state.touchMoved = true;
|
|
2469
|
+
if (state.longPressTimer) {
|
|
2470
|
+
clearTimeout(state.longPressTimer);
|
|
2471
|
+
state.longPressTimer = null;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
const speedScale = state.fov / ENGINE_CONFIG.defaultFov;
|
|
2475
|
+
const rotLock = Math.max(0, Math.min(1, (state.fov - 100) / (ENGINE_CONFIG.maxFov - 100)));
|
|
2476
|
+
const latFactor = 1 - rotLock * rotLock;
|
|
2477
|
+
state.targetLon += deltaX * ENGINE_CONFIG.dragSpeed * speedScale;
|
|
2478
|
+
state.targetLat += deltaY * ENGINE_CONFIG.dragSpeed * speedScale * latFactor;
|
|
2479
|
+
state.targetLat = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, state.targetLat));
|
|
2480
|
+
state.velocityX = deltaX * ENGINE_CONFIG.dragSpeed * speedScale;
|
|
2481
|
+
state.velocityY = deltaY * ENGINE_CONFIG.dragSpeed * speedScale * latFactor;
|
|
2482
|
+
state.lon = state.targetLon;
|
|
2483
|
+
state.lat = state.targetLat;
|
|
2484
|
+
} else if (touches.length === 2) {
|
|
2485
|
+
const t0 = touches[0];
|
|
2486
|
+
const t1 = touches[1];
|
|
2487
|
+
const newDistance = getTouchDistance(t0, t1);
|
|
2488
|
+
const scale = newDistance / state.pinchStartDistance;
|
|
2489
|
+
state.fov = state.pinchStartFov / scale;
|
|
2490
|
+
state.fov = Math.max(ENGINE_CONFIG.minFov, Math.min(ENGINE_CONFIG.maxFov, state.fov));
|
|
2491
|
+
handlers.onFovChange?.(state.fov);
|
|
2492
|
+
const center = getTouchCenter(t0, t1);
|
|
2493
|
+
const deltaX = center.x - state.lastMouseX;
|
|
2494
|
+
const deltaY = center.y - state.lastMouseY;
|
|
2495
|
+
state.lastMouseX = center.x;
|
|
2496
|
+
state.lastMouseY = center.y;
|
|
2497
|
+
const speedScale = state.fov / ENGINE_CONFIG.defaultFov;
|
|
2498
|
+
state.targetLon += deltaX * ENGINE_CONFIG.dragSpeed * speedScale * 0.5;
|
|
2499
|
+
state.targetLat += deltaY * ENGINE_CONFIG.dragSpeed * speedScale * 0.5;
|
|
2500
|
+
state.targetLat = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, state.targetLat));
|
|
2501
|
+
state.lon = state.targetLon;
|
|
2502
|
+
state.lat = state.targetLat;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
function onTouchEnd(e) {
|
|
2506
|
+
e.preventDefault();
|
|
2507
|
+
if (state.longPressTimer) {
|
|
2508
|
+
clearTimeout(state.longPressTimer);
|
|
2509
|
+
state.longPressTimer = null;
|
|
2510
|
+
}
|
|
2511
|
+
const remainingTouches = e.touches.length;
|
|
2512
|
+
if (remainingTouches === 0) {
|
|
2513
|
+
const now = performance.now();
|
|
2514
|
+
const duration = now - state.touchStartTime;
|
|
2515
|
+
const wasTap = !state.touchMoved && duration < ENGINE_CONFIG.tapMaxDuration && !state.longPressTriggered;
|
|
2516
|
+
if (wasTap) {
|
|
2517
|
+
const timeSinceLastTap = now - state.lastTapTime;
|
|
2518
|
+
const distFromLastTap = Math.sqrt(
|
|
2519
|
+
Math.pow(state.touchStartX - state.lastTapX, 2) + Math.pow(state.touchStartY - state.lastTapY, 2)
|
|
2520
|
+
);
|
|
2521
|
+
const isDoubleTap = timeSinceLastTap < ENGINE_CONFIG.doubleTapMaxDelay && distFromLastTap < ENGINE_CONFIG.doubleTapMaxDistance;
|
|
2522
|
+
const rect = renderer.domElement.getBoundingClientRect();
|
|
2523
|
+
const mX = state.touchStartX - rect.left;
|
|
2524
|
+
const mY = state.touchStartY - rect.top;
|
|
2525
|
+
mouseNDC.x = mX / rect.width * 2 - 1;
|
|
2526
|
+
mouseNDC.y = -(mY / rect.height) * 2 + 1;
|
|
2527
|
+
const syntheticEvent = {
|
|
2528
|
+
clientX: state.touchStartX,
|
|
2529
|
+
clientY: state.touchStartY
|
|
2530
|
+
};
|
|
2531
|
+
const hit = pick(syntheticEvent);
|
|
2532
|
+
if (isDoubleTap) {
|
|
2533
|
+
if (hit) {
|
|
2534
|
+
flyTo(hit.node.id, ENGINE_CONFIG.minFov);
|
|
2535
|
+
handlers.onSelect?.(hit.node);
|
|
2536
|
+
}
|
|
2537
|
+
state.lastTapTime = 0;
|
|
2538
|
+
state.lastTapX = 0;
|
|
2539
|
+
state.lastTapY = 0;
|
|
2540
|
+
} else {
|
|
2541
|
+
if (hit) {
|
|
2542
|
+
handlers.onSelect?.(hit.node);
|
|
2543
|
+
constellationLayer.setFocused(hit.node.id);
|
|
2544
|
+
if (hit.node.level === 2) setFocusedBook(hit.node.id);
|
|
2545
|
+
else if (hit.node.level === 3 && hit.node.parent) setFocusedBook(hit.node.parent);
|
|
2546
|
+
} else {
|
|
2547
|
+
setFocusedBook(null);
|
|
2548
|
+
}
|
|
2549
|
+
state.lastTapTime = now;
|
|
2550
|
+
state.lastTapX = state.touchStartX;
|
|
2551
|
+
state.lastTapY = state.touchStartY;
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
state.isDragging = false;
|
|
2555
|
+
state.dragMode = "none";
|
|
2556
|
+
state.touchCount = 0;
|
|
2557
|
+
} else if (remainingTouches === 1) {
|
|
2558
|
+
const touch = e.touches[0];
|
|
2559
|
+
state.lastMouseX = touch.clientX;
|
|
2560
|
+
state.lastMouseY = touch.clientY;
|
|
2561
|
+
state.touchCount = 1;
|
|
2562
|
+
state.dragMode = "camera";
|
|
2563
|
+
state.isDragging = true;
|
|
2564
|
+
state.velocityX = 0;
|
|
2565
|
+
state.velocityY = 0;
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
function onTouchCancel(e) {
|
|
2569
|
+
e.preventDefault();
|
|
2570
|
+
if (state.longPressTimer) {
|
|
2571
|
+
clearTimeout(state.longPressTimer);
|
|
2572
|
+
state.longPressTimer = null;
|
|
2573
|
+
}
|
|
2574
|
+
state.isDragging = false;
|
|
2575
|
+
state.dragMode = "none";
|
|
2576
|
+
state.touchCount = 0;
|
|
2577
|
+
state.velocityX = 0;
|
|
2578
|
+
state.velocityY = 0;
|
|
2579
|
+
}
|
|
2580
|
+
function onGesturePrevent(e) {
|
|
2581
|
+
e.preventDefault();
|
|
2582
|
+
}
|
|
2366
2583
|
function resize() {
|
|
2367
2584
|
const w = container.clientWidth || 1;
|
|
2368
2585
|
const h = container.clientHeight || 1;
|
|
@@ -2385,6 +2602,13 @@ function createEngine({
|
|
|
2385
2602
|
});
|
|
2386
2603
|
el.addEventListener("mouseleave", onWindowBlur);
|
|
2387
2604
|
window.addEventListener("blur", onWindowBlur);
|
|
2605
|
+
el.addEventListener("touchstart", onTouchStart, { passive: false });
|
|
2606
|
+
el.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
2607
|
+
el.addEventListener("touchend", onTouchEnd, { passive: false });
|
|
2608
|
+
el.addEventListener("touchcancel", onTouchCancel, { passive: false });
|
|
2609
|
+
el.addEventListener("gesturestart", onGesturePrevent, { passive: false });
|
|
2610
|
+
el.addEventListener("gesturechange", onGesturePrevent, { passive: false });
|
|
2611
|
+
el.addEventListener("gestureend", onGesturePrevent, { passive: false });
|
|
2388
2612
|
raf = requestAnimationFrame(tick);
|
|
2389
2613
|
}
|
|
2390
2614
|
function tick() {
|
|
@@ -2426,7 +2650,7 @@ function createEngine({
|
|
|
2426
2650
|
}
|
|
2427
2651
|
let panX = 0;
|
|
2428
2652
|
let panY = 0;
|
|
2429
|
-
if (!state.isDragging && isMouseInWindow && !currentConfig?.editable) {
|
|
2653
|
+
if (!state.isDragging && isMouseInWindow && !currentConfig?.editable && !isTouchDevice) {
|
|
2430
2654
|
const t = ENGINE_CONFIG.edgePanThreshold;
|
|
2431
2655
|
const inZoneX = mouseNDC.x < -1 + t || mouseNDC.x > 1 - t;
|
|
2432
2656
|
const inZoneY = mouseNDC.y < -1 + t || mouseNDC.y > 1 - t;
|
|
@@ -2479,8 +2703,9 @@ function createEngine({
|
|
|
2479
2703
|
} else if (!state.isDragging && !flyToActive) {
|
|
2480
2704
|
state.lon += state.velocityX;
|
|
2481
2705
|
state.lat += state.velocityY;
|
|
2482
|
-
|
|
2483
|
-
state.
|
|
2706
|
+
const damping = isTouchDevice ? ENGINE_CONFIG.touchInertiaDamping : ENGINE_CONFIG.inertiaDamping;
|
|
2707
|
+
state.velocityX *= damping;
|
|
2708
|
+
state.velocityY *= damping;
|
|
2484
2709
|
if (Math.abs(state.velocityX) < 1e-6) state.velocityX = 0;
|
|
2485
2710
|
if (Math.abs(state.velocityY) < 1e-6) state.velocityY = 0;
|
|
2486
2711
|
}
|
|
@@ -2652,6 +2877,13 @@ function createEngine({
|
|
|
2652
2877
|
el.removeEventListener("wheel", onWheel);
|
|
2653
2878
|
el.removeEventListener("mouseleave", onWindowBlur);
|
|
2654
2879
|
window.removeEventListener("blur", onWindowBlur);
|
|
2880
|
+
el.removeEventListener("touchstart", onTouchStart);
|
|
2881
|
+
el.removeEventListener("touchmove", onTouchMove);
|
|
2882
|
+
el.removeEventListener("touchend", onTouchEnd);
|
|
2883
|
+
el.removeEventListener("touchcancel", onTouchCancel);
|
|
2884
|
+
el.removeEventListener("gesturestart", onGesturePrevent);
|
|
2885
|
+
el.removeEventListener("gesturechange", onGesturePrevent);
|
|
2886
|
+
el.removeEventListener("gestureend", onGesturePrevent);
|
|
2655
2887
|
}
|
|
2656
2888
|
function dispose() {
|
|
2657
2889
|
stop();
|
|
@@ -2706,7 +2938,7 @@ var init_createEngine = __esm({
|
|
|
2706
2938
|
init_projections();
|
|
2707
2939
|
init_fader();
|
|
2708
2940
|
ENGINE_CONFIG = {
|
|
2709
|
-
minFov:
|
|
2941
|
+
minFov: 1,
|
|
2710
2942
|
maxFov: 135,
|
|
2711
2943
|
defaultFov: 50,
|
|
2712
2944
|
dragSpeed: 125e-5,
|
|
@@ -2718,7 +2950,20 @@ var init_createEngine = __esm({
|
|
|
2718
2950
|
horizonLockStrength: 0.05,
|
|
2719
2951
|
edgePanThreshold: 0.15,
|
|
2720
2952
|
edgePanMaxSpeed: 0.02,
|
|
2721
|
-
edgePanDelay: 250
|
|
2953
|
+
edgePanDelay: 250,
|
|
2954
|
+
// Touch-specific
|
|
2955
|
+
touchInertiaDamping: 0.85,
|
|
2956
|
+
// Snappier than mouse (0.92)
|
|
2957
|
+
tapMaxDuration: 300,
|
|
2958
|
+
// ms
|
|
2959
|
+
tapMaxDistance: 10,
|
|
2960
|
+
// px
|
|
2961
|
+
doubleTapMaxDelay: 300,
|
|
2962
|
+
// ms between taps
|
|
2963
|
+
doubleTapMaxDistance: 30,
|
|
2964
|
+
// px between tap locations
|
|
2965
|
+
longPressDelay: 500
|
|
2966
|
+
// ms to trigger long-press
|
|
2722
2967
|
};
|
|
2723
2968
|
ORDER_REVEAL_CONFIG = {
|
|
2724
2969
|
globalDim: 0.85,
|
|
@@ -2729,7 +2974,7 @@ var init_createEngine = __esm({
|
|
|
2729
2974
|
}
|
|
2730
2975
|
});
|
|
2731
2976
|
var StarMap = forwardRef(
|
|
2732
|
-
({ config, className, onSelect, onHover, onArrangementChange, onFovChange }, ref) => {
|
|
2977
|
+
({ config, className, onSelect, onHover, onArrangementChange, onFovChange, onLongPress }, ref) => {
|
|
2733
2978
|
const containerRef = useRef(null);
|
|
2734
2979
|
const engineRef = useRef(null);
|
|
2735
2980
|
useImperativeHandle(ref, () => ({
|
|
@@ -2752,7 +2997,8 @@ var StarMap = forwardRef(
|
|
|
2752
2997
|
onSelect,
|
|
2753
2998
|
onHover,
|
|
2754
2999
|
onArrangementChange,
|
|
2755
|
-
onFovChange
|
|
3000
|
+
onFovChange,
|
|
3001
|
+
onLongPress
|
|
2756
3002
|
});
|
|
2757
3003
|
engineRef.current.setConfig(config);
|
|
2758
3004
|
engineRef.current.start();
|
|
@@ -2768,8 +3014,8 @@ var StarMap = forwardRef(
|
|
|
2768
3014
|
engineRef.current?.setConfig?.(config);
|
|
2769
3015
|
}, [config]);
|
|
2770
3016
|
useEffect(() => {
|
|
2771
|
-
engineRef.current?.setHandlers?.({ onSelect, onHover, onArrangementChange, onFovChange });
|
|
2772
|
-
}, [onSelect, onHover, onArrangementChange, onFovChange]);
|
|
3017
|
+
engineRef.current?.setHandlers?.({ onSelect, onHover, onArrangementChange, onFovChange, onLongPress });
|
|
3018
|
+
}, [onSelect, onHover, onArrangementChange, onFovChange, onLongPress]);
|
|
2773
3019
|
return /* @__PURE__ */ jsx("div", { ref: containerRef, className, style: { width: "100%", height: "100%" } });
|
|
2774
3020
|
}
|
|
2775
3021
|
);
|