Full documentation: https://pannellum.2plot.dev — the dedicated dash-pannellum documentation site, with the complete API reference and deeper examples. This page is the quick-start overview.
dash-pannellum is a Dash component library that integrates the Pannellum panorama viewer into your Dash applications. It allows you to display interactive 360° panoramas, including equirectangular images, cube maps, and 360° videos. The component features tour mode with multiple scenes and hotspots, customizable camera controls, multi-resolution panorama support, and keyboard navigation for an immersive viewing experience.
Since 0.2.0 the viewer is also fully imperative: the lookAt prop pans and zooms the live camera, loadScene switches tour scenes, and callbackHotspots moves markers in real time — all without rebuilding the viewer. As of 0.4.0, the orientation prop turns on gyroscope look-around on mobile devices, so the device itself becomes the camera.
Installation
⭐️ Star this component on GitHub! Stay up to date on new releases and browse the codebase.
pip install dash-pannellum
Note:
dash-pannellum0.1.0+ requires Dash 4.2+ and is built against React 18. The Pannellum/video.js runtime loads from CDN at first render, so the browser needs internet access.
Quick Start
Display an interactive 360° equirectangular panorama with camera controls and adjustable viewing parameters.
# File: docs/dash_pannellum/simple.py
from dash import *
import dash_mantine_components as dmc
from dash_pannellum import DashPannellum
component = dmc.SimpleGrid(
cols={"base": 1, "sm": 1, "lg": 4},
children=[
dmc.Paper(dmc.Stack([
html.Div(id="view-pannellum"),
html.Label(id="pannellum-output"),
]),
id="intro-wrapper-dem",
style={"gridColumn": "1 / 4"},
),
dmc.Stack(
[
dmc.TextInput(
id='pannellum-panorama-url',
value='/assets/images/art_museum.jpg',
label='Panorama URL',
placeholder='Enter URL',
),
dmc.Select(
label="Select Panorama Type",
placeholder="Select one",
id="panorama-type",
value="equirectangular",
data=[
{"value": "equirectangular", "label": "Equirectangular"},
{"value": "tour", "label": "Tour"},
{"value": "multires", "label": "MultiRes"},
{"value": "video", "label": "Video"},
],
),
dmc.NumberInput(
id='pannellum-haov', label="haov prop", hideControls=True, mb=10, value=360, min=0, max=360,
),
dmc.NumberInput(
id='pannellum-vaov', label="vaov prop", hideControls=True, mb=10, value=180, min=0, max=180,
),
dmc.NumberInput(
id='pannellum-vOffset', label="vOffset prop", hideControls=True, mb=10, value=1, min=-90, max=90,
),
# dynamicWidth
# dmc.Checkbox(
# id="pannellum-custom-controls", label="customControls", checked=False, mb=10
# ),
dmc.Checkbox(
id="pannellum-show-center-dot", label="showCenterDot", checked=True, mb=10
),
dmc.Checkbox(
id="pannellum-autoload", label="autoLoad", checked=False, mb=10
),
],
style={'overflow-y': 'auto', 'max-height': '500px'},
),
dcc.Interval(id='interval-component', interval=100, n_intervals=0)
],
spacing="2rem",
)
@callback(
Output("view-pannellum", "children"),
Input("pannellum-panorama-url", "value"),
Input("panorama-type", "value"),
Input("pannellum-haov", "value"),
Input("pannellum-vaov", "value"),
Input("pannellum-vOffset", "value"),
# Input("pannellum-custom-controls", "checked"),
Input("pannellum-show-center-dot", "checked"),
Input("pannellum-autoload", "checked"),
)
def update_pannellum_output(url, panorama_type, haov, vaov, vOffset, showCenterDot, autoload):
print('selected props')
print(url, panorama_type, haov, vaov, vOffset, showCenterDot, autoload)
if not url:
return html.Div("No URL provided")
elif panorama_type == "equirectangular":
config = {
"type": "equirectangular",
"panorama": f"{url}",
"haov": float(haov),
"vaov": float(vaov),
"vOffset": float(vOffset),
}
return DashPannellum(
id=f"pannellum-example",
tour={"default": {"firstScene": "scene1"}, "scenes": {"scene1": config}},
showCenterDot=showCenterDot,
autoLoad=autoload,
width='100%',
height='400px',
)
elif panorama_type == 'tour':
tour_config = {
"default": {
"firstScene": "circle",
"author": "Pip Install Python",
"sceneFadeDuration": 1000,
},
"scenes": {
"circle": {
"title": "Dash Pannellum",
"hfov": 110,
"pitch": -3,
"yaw": 117,
"type": "equirectangular",
"panorama": f"{url}",
"hotSpots": [
{
"pitch": -2.1,
"yaw": 132.9,
"type": "scene",
"text": "Spring House or Dairy",
"sceneId": "house"
}
]
},
"house": {
"title": "Spring House or Dairy",
"hfov": 110,
"yaw": 5,
"type": "equirectangular",
"panorama": "https://pannellum.org/images/bma-0.jpg",
"hotSpots": [
{
"pitch": -0.6,
"yaw": 37.1,
"type": "scene",
"text": "Mason Circle",
"sceneId": "circle",
"targetYaw": -23,
"targetPitch": 2
}
]
}
}
}
return DashPannellum(
id='pannellum-example',
tour=tour_config,
showCenterDot=showCenterDot,
width='100%',
height='400px',
autoLoad=autoload
)
elif panorama_type == 'multires':
multiRes_config = {
"basePath": "https://pannellum.org/images/multires/library",
"path": "/%l/%s%y_%x",
"fallbackPath": "/fallback/%s",
"extension": "jpg",
"tileResolution": 512,
"maxLevel": 6,
"cubeResolution": 8432,
}
return DashPannellum(
id='pannellum-example',
multiRes=multiRes_config,
showCenterDot=showCenterDot,
width='100%',
height='400px',
autoLoad=autoload
)
elif panorama_type == 'video':
video_config = {
"sources": [
{"src": "https://bitmovin-a.akamaihd.net/content/playhouse-vr/progressive.mp4", "type": "video/mp4"},
],
"poster": "https://bitmovin-a.akamaihd.net/content/playhouse-vr/poster.jpg"
}
return DashPannellum(
id='pannellum-example',
video=video_config,
showCenterDot=showCenterDot,
width='100%',
height='400px',
autoLoad=autoload
)
return html.Div("Something went wrong")
@callback(
Output('pannellum-output', 'children'),
Input('pannellum-example', 'pitch'),
Input('pannellum-example', 'yaw'),
Input('interval-component', 'n_intervals'),
prevent_initial_call=True
)
def update_video_output(pitch, yaw, n):
if pitch is not None and yaw is not None:
return f'Camera Position - Pitch: {pitch:.2f}, Yaw: {yaw:.2f}'
return 'Camera Position - Pitch: 0.00, Yaw: 0.00'
Basic Panorama
Create a simple panorama viewer with basic configuration.
# File: docs/dash_pannellum/basic.py
from dash import html
import dash_pannellum
component = html.Div([
dash_pannellum.DashPannellum(
id='panorama',
tour={
"default": {
"firstScene": "scene1",
"sceneFadeDuration": 1000
},
"scenes": {
"scene1": {
"title": "Example Panorama",
"hfov": 110,
"pitch": -3,
"yaw": 117,
"type": "equirectangular",
"panorama": "/assets/images/landscape.jpg"
}
}
},
autoLoad=True,
width='100%',
height='400px',
)
])
Tour Mode
Tour mode enables navigation between multiple connected panorama scenes with interactive hotspots. Users can click hotspots to jump between different viewpoints, creating an immersive multi-scene experience.
# File: docs/dash_pannellum/tours.py
from dash import html
import dash_pannellum
component = html.Div([
dash_pannellum.DashPannellum(
id='panorama',
tour={
"default": {
"firstScene": "circle",
"author": "Pip Install Python",
"sceneFadeDuration": 1000,
},
"scenes": {
"circle": {
"title": "Dash Pannellum",
"hfov": 110,
"pitch": -3,
"yaw": 117,
"type": "equirectangular",
"panorama": "https://pannellum.org/images/alma.jpg",
"hotSpots": [
{
"pitch": -2.1,
"yaw": 132.9,
"type": "scene",
"text": "Spring House or Dairy",
"sceneId": "house"
}
]
},
"house": {
"title": "Spring House or Dairy",
"hfov": 110,
"yaw": 5,
"type": "equirectangular",
"panorama": "https://pannellum.org/images/bma-0.jpg",
"hotSpots": [
{
"pitch": -0.6,
"yaw": 37.1,
"type": "scene",
"text": "Mason Circle",
"sceneId": "circle",
"targetYaw": -23,
"targetPitch": 2
}
]
}
}
},
autoLoad=True,
width='100%',
height='400px',
)
])
Tour Configuration:
Each tour consists of a default object and a scenes dictionary:
default.firstScene: ID of the initial scene to displaydefault.sceneFadeDuration: Transition duration in milliseconds between scenesscenes: Dictionary of scene configurations, each with its own panorama and hotspots
Hotspot Configuration:
pitch: Vertical position in degreesyaw: Horizontal position in degreestype:"scene"for scene navigation hotspotstext: Tooltip text displayed on hoversceneId: Target scene ID to navigate totargetYaw(optional): Camera yaw after transitiontargetPitch(optional): Camera pitch after transition
Partial Panorama
Display panoramas that don't cover the full 360° horizontally or 180° vertically by specifying viewing extents using horizontal angle of view (haov), vertical angle of view (vaov), and vertical offset (vOffset).
# File: docs/dash_pannellum/partial_panorama.py
from dash import html
import dash_pannellum
component = html.Div([
dash_pannellum.DashPannellum(
id='partial-panorama-component',
tour={"default": {"firstScene": "scene1"}, "scenes": {"scene1":
{
"type": "equirectangular",
"panorama": "https://archive.org/download/SalinaKansas1916Postcard/Salina%20Kansas%2C%201916%20Postcard%2C%20Front.jpg",
"haov": 149.87,
"vaov": 54.15,
"vOffset": 1.17
}
}
},
width='100%',
height='400px',
autoLoad=True
)
])
Viewing Parameters:
haov: Horizontal angle of view in degrees (e.g., 149.87)vaov: Vertical angle of view in degrees (e.g., 54.15)vOffset: Vertical offset in degrees, useful when panorama is not vertically centered (e.g., 1.17)
These parameters allow precise control over which portion of the panorama is visible and how it's framed within the viewer.
360° Video Panorama
Display interactive 360° video content with standard video controls.
# File: docs/dash_pannellum/video.py
from dash import html
import dash_pannellum
component = html.Div([
dash_pannellum.DashPannellum(
id='panorama',
video={
"sources": [
{"src": "https://cdn.bitmovin.com/content/assets/playhouse-vr/progressive.mp4", "type": "video/mp4"},
],
"poster": "https://cdn.bitmovin.com/content/assets/playhouse-vr/poster.jpg"
},
autoLoad=True,
width='100%',
height='400px',
)
])
Video Configuration:
sources: Array of video source objects withsrc(URL) andtype(MIME type)poster: URL to poster image displayed before video loads
The component supports standard HTML5 video formats. Users can interact with the video using typical video controls while maintaining the ability to pan around the 360° view.
Using Callbacks
Track the viewer's current state (camera position, zoom, loaded status, active scene) using Dash callbacks. The component provides read-only properties that update as the user interacts with the panorama. View-state updates are throttled to 4 per second and change-detected, so idle viewers fire nothing.
from dash import callback, Input, Output
@callback(
Output('output-div', 'children'),
Input('panorama', 'loaded'),
Input('panorama', 'pitch'),
Input('panorama', 'yaw'),
Input('panorama', 'hfov'),
Input('panorama', 'currentScene')
)
def update_output(loaded, pitch, yaw, hfov, current_scene):
"""Display current panorama state"""
if loaded and pitch is not None and yaw is not None:
return f'Scene: {current_scene}, Pitch: {pitch:.2f}°, Yaw: {yaw:.2f}°, Zoom: {hfov:.1f}°'
return 'Loading panorama...'
Available Read-Only Callback Properties:
loaded: Boolean indicating if panorama has finished loadingpitch: Current vertical camera angle (-90° to 90°)yaw: Current horizontal camera angle (-180° to 180°)hfov: Current horizontal field of view — the zoom level, in degreescurrentScene: ID of the active scene in tour modelastClickedHotspot:nameof the last clicked callback hotspot (see Callback Hotspots)orientationSupported/orientationActive: gyroscope truth props (see Gyroscope Look-Around)
Warning: These properties are outputs only — use them as callback
Inputs, never asOutputs. Writing topitch/yaw/hfovdoes not move the camera. To drive the camera, write thelookAtprop instead; set the initial orientation in the scene config.
Driving the Camera with lookAt
The lookAt prop (added in 0.2.0) is an imperative camera write: set {pitch, yaw, hfov, animated} from any callback and the live viewer pans and zooms in place — no rebuild, no flash, no camera reset. Omitted fields keep their current value, and animated is the transition duration in milliseconds. Combined with the read-only pitch/yaw/hfov outputs, this gives you a full "fly-to" pattern from buttons, clicked hotspots, or any external event.
# File: docs/dash_pannellum/camera_control.py
import dash_mantine_components as dmc
from dash import callback, ctx, Input, Output
from dash_pannellum import DashPannellum
# Named camera targets. Omitted fields keep their current value,
# so "Zoom In" only touches hfov and leaves pitch/yaw alone.
TARGETS = {
"pannellum-lookat-btn-house": {"pitch": -2.1, "yaw": 132.9, "hfov": 60},
"pannellum-lookat-btn-sky": {"pitch": 55, "hfov": 100},
"pannellum-lookat-btn-zoom": {"hfov": 50},
"pannellum-lookat-btn-reset": {"pitch": -3, "yaw": 117, "hfov": 110},
}
component = dmc.Stack(
[
DashPannellum(
id="pannellum-lookat-viewer",
tour={
"default": {"firstScene": "circle"},
"scenes": {
"circle": {
"type": "equirectangular",
"panorama": "https://pannellum.org/images/alma.jpg",
"hfov": 110,
"pitch": -3,
"yaw": 117,
}
},
},
autoLoad=True,
width="100%",
height="400px",
),
dmc.Group(
[
dmc.Button("Spring House", id="pannellum-lookat-btn-house", size="xs"),
dmc.Button("Look Up", id="pannellum-lookat-btn-sky", size="xs"),
dmc.Button("Zoom In", id="pannellum-lookat-btn-zoom", size="xs"),
dmc.Button(
"Reset View",
id="pannellum-lookat-btn-reset",
size="xs",
variant="outline",
),
]
),
dmc.Text(id="pannellum-lookat-readout", size="sm", c="dimmed"),
],
gap="sm",
)
@callback(
Output("pannellum-lookat-viewer", "lookAt"),
Input("pannellum-lookat-btn-house", "n_clicks"),
Input("pannellum-lookat-btn-sky", "n_clicks"),
Input("pannellum-lookat-btn-zoom", "n_clicks"),
Input("pannellum-lookat-btn-reset", "n_clicks"),
prevent_initial_call=True,
)
def fly_to(*_):
"""Write lookAt — the live viewer pans/zooms in place, no rebuild."""
return {**TARGETS[ctx.triggered_id], "animated": 1000}
@callback(
Output("pannellum-lookat-readout", "children"),
Input("pannellum-lookat-viewer", "pitch"),
Input("pannellum-lookat-viewer", "yaw"),
Input("pannellum-lookat-viewer", "hfov"),
prevent_initial_call=True,
)
def readout(pitch, yaw, hfov):
"""pitch / yaw / hfov are read-only Inputs that report the camera back."""
if pitch is None or yaw is None:
return "Camera: waiting for viewer..."
hfov_text = f", hfov {hfov:.1f}°" if hfov is not None else ""
return f"Camera: pitch {pitch:.1f}°, yaw {yaw:.1f}°{hfov_text}"
lookAt keys:
pitch(optional): Target vertical angle in degreesyaw(optional): Target horizontal angle in degreeshfov(optional): Target zoom (horizontal field of view) in degreesanimated(optional): Transition duration in ms (default 1000; use a small value like 220 for joystick-style continuous steering)
For high-frequency steering (a joystick, keyboard, or game loop), skip the server round-trip and write from a clientside callback or plain JS:
window.dash_clientside.set_props('panorama', {lookAt: {yaw: bearing, animated: 220}});
lookAt works in image panorama (tour) mode; it does not reach multiRes or video viewers. A lookAt write that lands while the viewer is still booting is dropped — initial orientation belongs in the scene config.
Related imperative props — the same no-rebuild philosophy applies to:
loadScene: set to a scene ID from the tour config to switch scenes without rebuilding the viewer. Unknown IDs and the already-active scene are ignored, so it's safe to reflect. Pair withpreloadScenes(default on) for instant jumps.callbackHotspots: move or replace hotspot markers live (see next section).
Callback Hotspots
callbackHotspots adds hotspots that report clicks back to Python — separate from the tour's own hotSpots. Keys are scene IDs; each entry's name is written to the read-only lastClickedHotspot prop on click:
from dash import callback, Input, Output
from dash_pannellum import DashPannellum
DashPannellum(
id='panorama',
tour=tour,
callbackHotspots={
"lobby": [
{"pitch": -1.2, "yaw": 122.0, "type": "info",
"text": "Reception desk", "name": "reception"},
],
},
)
@callback(
Output('info-panel', 'children'),
Input('panorama', 'lastClickedHotspot'),
prevent_initial_call=True,
)
def on_hotspot(name):
return INFO[name]
Live updates with per-name diffing (0.3.1): outputting a new callbackHotspots dict from a callback never rebuilds the viewer, and the update is diffed per name:
- Unchanged hotspots are left untouched
- Position-only changes move the existing DOM node in place — the marker keeps its hover state and stays clickable mid-flight
- Changes to
text/type/cssClassrecreate just that one hotspot - Names that disappear are removed
This means markers can drift every tick as real DOM hotspots:
@callback(Output('panorama', 'callbackHotspots'), Input('tick', 'n_intervals'))
def drift(n):
return {"main": [project_to_yaw_pitch(e) for e in world.entities]}
Keep name stable per entity — it's the diff key. If you encode a tick counter into name, every update becomes a remove-and-re-add again.
Tip — authoring hotspot coordinates: set showCenterDot=True (a crosshair at screen center), stream pitch/yaw into a readout callback, aim the dot at the target, and copy the values into your hotspot config. Remove the dot for production.
Gyroscope Look-Around
New in 0.4.0. The orientation prop requests gyroscope steering — point the phone around and the panorama follows. It's imperative (no rebuild): set it to True to engage, False to release. Two read-only props report the truth: orientationSupported (the device/browser can gyro-steer at all) and orientationActive (the gyro is steering right now — False if permission was denied, and Pannellum pauses it while the user drags the panorama).
# File: docs/dash_pannellum/gyro.py
import dash_mantine_components as dmc
from dash import callback, clientside_callback, Input, Output
from dash_pannellum import DashPannellum
component = dmc.Stack(
[
DashPannellum(
id="pannellum-gyro-viewer",
tour={
"default": {"firstScene": "house"},
"scenes": {
"house": {
"type": "equirectangular",
"panorama": "https://pannellum.org/images/bma-0.jpg",
"hfov": 110,
}
},
},
autoLoad=True,
width="100%",
height="400px",
),
dmc.Group(
[
dmc.Switch(
id="pannellum-gyro-switch",
label="Gyroscope look-around",
checked=False,
),
dmc.Badge(
"Checking sensors...",
id="pannellum-gyro-supported",
color="gray",
variant="light",
),
dmc.Badge(
"Gyro idle",
id="pannellum-gyro-active",
color="gray",
variant="light",
),
]
),
dmc.Text(
"Gyro steering needs a mobile device with motion sensors, served over "
"HTTPS. On desktop the switch is a no-op and the panorama stays "
"drag-to-look — nothing breaks.",
size="sm",
c="dimmed",
),
],
gap="sm",
)
# The orientation write MUST be clientside: iOS 13+ only shows the
# motion-permission prompt inside a user-gesture window, so the prop has
# to be set synchronously on the tap — a server round-trip is too late.
clientside_callback(
"function(on) { return Boolean(on); }",
Output("pannellum-gyro-viewer", "orientation"),
Input("pannellum-gyro-switch", "checked"),
prevent_initial_call=True,
)
@callback(
Output("pannellum-gyro-supported", "children"),
Output("pannellum-gyro-supported", "color"),
Output("pannellum-gyro-active", "children"),
Output("pannellum-gyro-active", "color"),
Input("pannellum-gyro-viewer", "orientationSupported"),
Input("pannellum-gyro-viewer", "orientationActive"),
)
def gyro_status(supported, active):
"""orientationSupported / orientationActive are read-only truth props."""
if supported:
supported_badge = ("Gyro supported", "green")
else:
supported_badge = ("Not supported on this device", "gray")
if active:
active_badge = ("Gyro steering", "teal")
else:
active_badge = ("Gyro idle", "gray")
return (*supported_badge, *active_badge)
iOS requires a clientside callback on a direct tap. iOS 13+ only shows the motion-permission prompt inside a user-gesture window, so the orientation write must happen synchronously on the tap — a server callback round-trip is too late:
from dash import clientside_callback, Input, Output
clientside_callback(
"function(on) { return Boolean(on); }",
Output('panorama', 'orientation'),
Input('gyro-switch', 'checked'),
prevent_initial_call=True,
)
Gyro support constraints — Pannellum gates orientation on all three of:
DeviceOrientationEventbeing available (motion sensors)- A mobile user agent
- Literal
https:— Pannellum checkslocation.protocol, so plain-HTTPlocalhostreports unsupported even though browsers would allow the sensor there. Use a TLS dev cert or a tunnel to test on a phone.
On desktop the feature degrades gracefully: orientationSupported stays False, the switch is a no-op, and the panorama remains drag-to-look. Turn orientation off before running directed lookAt sequences — a camera fighting the gyroscope feels broken.
Keyboard Controls
The component supports keyboard navigation for improved user experience:
- Arrow Keys: Pan the view (←→ horizontal, ↑↓ vertical)
- Shift: Zoom in
- Control/Ctrl: Zoom out
- F: Toggle fullscreen mode
Component Properties
| Property | Type | Default | Description |
|---|---|---|---|
id | string | Required | Unique identifier for the component used in Dash callbacks. |
width | string | '600px' | Width of the panorama viewer (any CSS size, e.g., '100%', '800px'). |
height | string | '400px' | Height of the panorama viewer (any CSS size, e.g., '400px', '100vh'). |
tour | dict | None | Tour mode config: {default: {firstScene, ...}, scenes: {sceneId: {...}}}. A single panorama is a tour with one scene. A scene may set panoramaCanvasId (DOM id of a <canvas>) instead of panorama for dynamic canvas mode. Live — changing it rebuilds the viewer. |
multiRes | dict | None | Multi-resolution (tiled) panorama config: basePath, path, fallbackPath, extension, tileResolution, maxLevel, cubeResolution. Live. |
video | dict | None | 360° video config: {sources: [{src, type}], poster}. Rendered through video.js. Live. |
autoLoad | bool | True | If true, the panorama loads automatically. If false, user must click to load. |
compass | bool | False | If true, displays a compass heading indicator in the viewer. |
northOffset | number | 0 | Offset, in degrees, of the center of the panorama from North. |
customControls | bool | False | If true, hides the built-in zoom/fullscreen controls so you can build your own with Dash components. |
showCenterDot | bool | False | If true, displays a center dot — useful as a crosshair when authoring hotspot positions. |
useHttpStreaming | bool | False | If true, loads the video.js HTTP streaming plugin so HLS/DASH sources (e.g. live streams) can play as 360° video. |
callbackHotspots | dict | {} | Hotspots that report clicks to Dash: {sceneId: [{pitch, yaw, type, text, name}]}. Diffed per-name in place — no rebuild (0.3.1). |
lookAt | dict | None | Imperative camera write: {pitch, yaw, hfov, animated} pans/zooms the live viewer with no rebuild. Omitted keys keep their value; animated is ms (default 1000). Image panorama modes only. |
loadScene | string | None | Imperative tour scene switch by scene ID — no rebuild. Unknown IDs and the active scene are ignored. |
preloadScenes | bool | True | Prefetch the other scenes' panoramas once the viewer is up, so tour jumps don't show a loading box. |
hideLoadingSpinner | bool | False | Suppress Pannellum's "Loading..." box for this viewer. |
dynamicUpdate | bool | False | Re-upload the panorama texture every frame — required for live panoramaCanvasId canvas scenes. Leave false for static panoramas. |
orientation | bool | False | Request gyroscope look-around (0.4.0). Mobile + HTTPS only; on iOS, set from a clientside callback on a direct user tap. |
orientationSupported | bool | (read-only) | True when the device/browser can drive the camera from the gyroscope (motion sensors + mobile browser + literal https:). |
orientationActive | bool | (read-only) | True while gyro look-around is actively steering (false if permission was denied or while the user drags). |
loaded | bool | (read-only) | Indicates whether the panorama has finished loading. |
pitch | number | (read-only) | Current vertical camera angle in degrees (-90 to 90). Throttled to 4 updates/s. |
yaw | number | (read-only) | Current horizontal camera angle in degrees (-180 to 180). Throttled to 4 updates/s. |
hfov | number | (read-only) | Current horizontal field of view (zoom) in degrees. Throttled to 4 updates/s. |
currentScene | string | (read-only) | ID of the currently active scene in tour mode. |
lastClickedHotspot | string | (read-only) | name of the last clicked callback hotspot. |
Read-only props are callback Inputs — never write to them from an Output. Use lookAt, loadScene and callbackHotspots to act on a running viewer; changing tour/multiRes/video (and other "live" config props) tears down and re-initializes it.
Multi-Resolution Configuration:
When using multiRes for high-quality panoramas, the configuration requires:
basePath: Base URL path to tile directorypath: Tile path pattern (e.g.,"/%l/%s%y_%x")fallbackPath: Fallback path for missing tilesextension: Image file extension (e.g.,"jpg")tileResolution: Resolution of each tile in pixelsmaxLevel: Maximum zoom level availablecubeResolution: Total resolution of cube faces
Contributing
Contributions to dash-pannellum are welcome! Please refer to the project's issues on GitHub for any feature requests or bug reports.
License
This project is licensed under the MIT License.