@ericchen1990/pano-view 0.1.5 → 0.1.6

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 CHANGED
@@ -228,8 +228,8 @@ export function PlacementExample() {
228
228
 
229
229
  `normalizePanoPosition`, `normalizePanoYaw`, `clampPanoPitch`, and
230
230
  `vector3ToPanoPosition` are also exported for controlled authoring flows. Yaw
231
- is normalized to `[-180, 180)`. Pitch is clamped to `[-89.9, 89.9]` to avoid
232
- the spherical-coordinate singularity at the poles.
231
+ is normalized to `[-180, 180)`. Pitch is clamped to `[-90, 90]`; at either
232
+ pole, yaw is normalized to `0` because it does not identify a unique point.
233
233
 
234
234
  ## Shared hotspot contract and saved definitions
235
235
 
@@ -337,6 +337,9 @@ placement properties:
337
337
  - `scaleMode="fov"` (default) lets a hotspot grow when the user zooms in.
338
338
  `scaleMode="fixed"` compensates for FOV changes and keeps its screen size
339
339
  close to the size at `referenceFov` (default `75`).
340
+ - `rotation` rotates the hotspot around its own normal in degrees. `scale`
341
+ applies an overall positive multiplier to its angular width and height and
342
+ defaults to `1`.
340
343
 
341
344
  ```tsx
342
345
  <ImageHotspot
@@ -347,6 +350,8 @@ placement properties:
347
350
  height={6}
348
351
  mode="billboard"
349
352
  distance={14}
353
+ rotation={-12}
354
+ scale={1.25}
350
355
  scaleMode="fixed"
351
356
  src="/hotspots/callout.webp"
352
357
  />
package/dist/index.cjs CHANGED
@@ -52,7 +52,7 @@ var import_react4 = require("react");
52
52
  var import_fiber = require("@react-three/fiber");
53
53
  var import_react = require("react");
54
54
  var import_three = require("three");
55
- var MAX_PITCH = 89.9;
55
+ var MAX_PITCH = 90;
56
56
  var INERTIA_ROTATION_DAMPING = 8;
57
57
  var INERTIA_ZOOM_DAMPING = 12;
58
58
  var DEFAULT_ROTATE_DAMPING = 14;
@@ -578,9 +578,10 @@ var import_three3 = require("three");
578
578
  var import_three2 = require("three");
579
579
 
580
580
  // src/hotspot/types.ts
581
- var MAX_HOTSPOT_PITCH = 89.9;
581
+ var MAX_HOTSPOT_PITCH = 90;
582
582
 
583
583
  // src/hotspot/coordinates.ts
584
+ var POLE_EPSILON_DEGREES = 1e-6;
584
585
  function normalizePanoYaw(yaw) {
585
586
  if (!Number.isFinite(yaw)) {
586
587
  return 0;
@@ -591,12 +592,18 @@ function clampPanoPitch(pitch) {
591
592
  if (!Number.isFinite(pitch)) {
592
593
  return 0;
593
594
  }
594
- return import_three2.MathUtils.clamp(pitch, -MAX_HOTSPOT_PITCH, MAX_HOTSPOT_PITCH);
595
+ const clamped = import_three2.MathUtils.clamp(
596
+ pitch,
597
+ -MAX_HOTSPOT_PITCH,
598
+ MAX_HOTSPOT_PITCH
599
+ );
600
+ return Math.abs(clamped) >= MAX_HOTSPOT_PITCH - POLE_EPSILON_DEGREES ? Math.sign(clamped) * MAX_HOTSPOT_PITCH : clamped;
595
601
  }
596
602
  function normalizePanoPosition(position) {
603
+ const pitch = clampPanoPitch(position.pitch);
597
604
  return {
598
- yaw: normalizePanoYaw(position.yaw),
599
- pitch: clampPanoPitch(position.pitch)
605
+ yaw: Math.abs(pitch) === MAX_HOTSPOT_PITCH ? 0 : normalizePanoYaw(position.yaw),
606
+ pitch
600
607
  };
601
608
  }
602
609
  function panoPositionToVector3(position, radius = 1) {
@@ -724,7 +731,7 @@ var PanoView = (0, import_react4.forwardRef)(
724
731
  const normalizedInitialView = (0, import_react4.useMemo)(
725
732
  () => ({
726
733
  yaw: initialView?.yaw ?? DEFAULT_VIEW.yaw,
727
- pitch: initialView?.pitch ?? DEFAULT_VIEW.pitch,
734
+ pitch: clampPanoPitch(initialView?.pitch ?? DEFAULT_VIEW.pitch),
728
735
  fov: Math.max(
729
736
  normalizedMinFov,
730
737
  Math.min(initialView?.fov ?? DEFAULT_VIEW.fov, normalizedMaxFov)
@@ -2449,6 +2456,9 @@ function angularSizeToWorldSize(size, radius) {
2449
2456
  const safeSize = Number.isFinite(size) ? import_three9.MathUtils.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
2450
2457
  return 2 * radius * Math.tan(import_three9.MathUtils.degToRad(safeSize) / 2);
2451
2458
  }
2459
+ function resolveScale(scale) {
2460
+ return Number.isFinite(scale) && scale > 0 ? scale : 1;
2461
+ }
2452
2462
  function resolveDistance(placement, distance, width, height) {
2453
2463
  const maximumDistance = maximumHotspotDistance(width, height);
2454
2464
  if (placement === "surface") {
@@ -2513,6 +2523,7 @@ function HotspotAnchor({
2513
2523
  position,
2514
2524
  width,
2515
2525
  height,
2526
+ scale = 1,
2516
2527
  useAngularScale = true,
2517
2528
  focusContent,
2518
2529
  mode = "billboard",
@@ -2541,7 +2552,15 @@ function HotspotAnchor({
2541
2552
  const normalizedPosition = normalizePanoPosition(position);
2542
2553
  const rendering = internalOrientation && internalPlacement ? { orientation: internalOrientation, placement: internalPlacement } : HOTSPOT_MODE_RENDERING[mode];
2543
2554
  const { orientation: orientation2, placement } = rendering;
2544
- const resolvedDistance = resolveDistance(placement, distance, width, height);
2555
+ const resolvedScale = resolveScale(scale);
2556
+ const scaledWidth = width * resolvedScale;
2557
+ const scaledHeight = height * resolvedScale;
2558
+ const resolvedDistance = resolveDistance(
2559
+ placement,
2560
+ distance,
2561
+ scaledWidth,
2562
+ scaledHeight
2563
+ );
2545
2564
  const worldPosition = (0, import_react9.useMemo)(
2546
2565
  () => panoPositionToVector3(normalizedPosition, resolvedDistance),
2547
2566
  [normalizedPosition.pitch, normalizedPosition.yaw, resolvedDistance]
@@ -2550,8 +2569,8 @@ function HotspotAnchor({
2550
2569
  () => createSurfaceQuaternion(normalizedPosition),
2551
2570
  [normalizedPosition.pitch, normalizedPosition.yaw]
2552
2571
  );
2553
- const worldWidth = angularSizeToWorldSize(width, resolvedDistance);
2554
- const worldHeight = angularSizeToWorldSize(height, resolvedDistance);
2572
+ const worldWidth = angularSizeToWorldSize(scaledWidth, resolvedDistance);
2573
+ const worldHeight = angularSizeToWorldSize(scaledHeight, resolvedDistance);
2555
2574
  const focusGeometry = (0, import_react9.useMemo)(() => {
2556
2575
  const planeGeometry = new import_three9.PlaneGeometry(1, 1);
2557
2576
  const geometry = new import_three9.EdgesGeometry(planeGeometry);