Skip to main content
The Markers plugin lets you place points of interest on the panorama. Markers can be images, HTML content, SVG shapes, or geographic polygons and polylines. Each marker supports tooltips, descriptions, visibility controls, and click events.

Installation

npm install @photo-sphere-viewer/markers-plugin
This plugin requires its stylesheet. Import @photo-sphere-viewer/markers-plugin/index.css using your preferred method, or add the CDN link to your <head>.

Usage

import { Viewer } from '@photo-sphere-viewer/core';
import { MarkersPlugin } from '@photo-sphere-viewer/markers-plugin';

const viewer = new Viewer({
    panorama: 'path/to/panorama.jpg',
    plugins: [
        MarkersPlugin.withConfig({
            markers: [
                {
                    id: 'new-marker',
                    position: { yaw: '45deg', pitch: '0deg' },
                    image: 'assets/pin-red.png',
                    size: { width: 32, height: 32 },
                },
            ],
        }),
    ],
});

const markersPlugin = viewer.getPlugin(MarkersPlugin);

markersPlugin.addEventListener('select-marker', ({ marker }) => {
    markersPlugin.updateMarker({
        id: marker.id,
        image: 'assets/pin-blue.png',
    });
});

Marker types

Every marker definition requires exactly one type property. The available types are:

image

Renders a flat image above the viewer. Requires size.
{
    id: 'marker-1',
    image: 'pin-red.png',
    position: { yaw: 0, pitch: 0 },
    size: { width: 32, height: 32 },
}

imageLayer

Renders an image inside the panorama scene for natural movement and depth. Can be positioned with a single position + size, or by providing four corner coordinates.
// Single position + size
{
    id: 'marker-1',
    imageLayer: 'pin-red.png',
    position: { yaw: 0, pitch: 0 },
    size: { width: 32, height: 32 },
}

// Four corner positions (clockwise from top-left)
{
    id: 'marker-2',
    imageLayer: 'billboard.png',
    position: [
        { yaw: -0.2, pitch: 0.2 },
        { yaw: 0.2, pitch: 0.2 },
        { yaw: 0.2, pitch: -0.2 },
        { yaw: -0.2, pitch: -0.2 },
    ],
}
imageLayer renders inside the 3D scene while image renders flat above the viewer. Use imageLayer for a more natural appearance.

Plugin configuration

markers
MarkerConfig[]
Initial list of markers. Not updatable after init — use the setMarkers() method instead.
defaultHoverScale
boolean | number | object
default:"null"
Default hover scale applied to all markers. Set to true for 2× scale over 100 ms with a linear easing. Can be an object with amount, duration, and easing fields. Override per marker with hoverScale.
gotoMarkerSpeed
string | number
default:"'8rpm'"
Default animation speed for the gotoMarker method. Updatable.
clickEventOnMarker
boolean
default:"false"
When true, a click event fires on the viewer in addition to the select-marker event. Updatable.
lang
object
Localization strings merged with the main viewer lang object.
lang: {
    markers: 'Markers',
    markersList: 'Markers list',
}

Marker options

The following options apply when defining or updating a marker.
id
string
required
Unique identifier for the marker.
position
{ yaw, pitch } | { textureX, textureY } | array
required
Position in spherical coordinates (radians/degrees) or texture coordinates (pixels). For imageLayer and videoLayer, you can supply an array of four corner positions instead. Ignored for polygons and polylines.
size
{ width, height }
Size of the marker in pixels. Required for image and imageLayer; recommended for html and element. Ignored for polygons and polylines.
rotation
string | number | { yaw, pitch, roll }
Rotation applied to the marker in degrees or radians. For 2D markers only roll applies; for 3D layer markers all axes apply (ignored when position is an array). Ignored for polygons and polylines.
scale
number[] | { zoom: number[], yaw: number[] }
Scale the marker based on zoom level and/or horizontal angle. Each sub-array is [scale at min, scale at max]. Ignored for polygons, polylines, and layers.
scale: {
    zoom: [0.5, 1],   // half size at minimum zoom
    yaw: [1, 1.5],    // 1.5× size at the side of the screen
}
hoverScale
boolean | number | object
default:"null"
Override the global defaultHoverScale for this marker. Set to false to disable scaling. Accepts the same shape as defaultHoverScale. Ignored for polygons, polylines, and layers.
opacity
number
default:"1"
Opacity of the marker.
zIndex
number
default:"1"
Stacking order. Note: imageLayer/videoLayer markers always render first, then polygons/polylines, then standard markers.
className
string
CSS class(es) added to the marker element. Ignored for imageLayer and videoLayer.
style
object
CSS properties set on the marker element (e.g. backgroundColor, cursor). For imageLayer and videoLayer only cursor is applicable.
style: {
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
    cursor: 'help',
}
svgStyle
object
SVG properties set on polygon, polyline, and SVG shape markers (e.g. fill, stroke, strokeWidth).
svgStyle: {
    fill: 'rgba(0, 0, 0, 0.5)',
    stroke: '#ff0000',
    strokeWidth: '2px',
}
chromaKey
object
default:"{ enabled: false }"
Make a color transparent (green screen / blue screen). Only applicable to imageLayer and videoLayer.
chromaKey: {
    enabled: true,
    color: 0x00ff00,       // or { r: 0, g: 255, b: 0 }
    similarity: 0.2,
    smoothness: 0.2,
}
anchor
string
default:"'center center'"
Placement of the marker relative to its position. Accepts any CSS position string such as 'bottom center' or '20% 80%'. Ignored for polygons and polylines.
zoomLvl
number
Zoom level applied when gotoMarker() is called or when the marker is clicked in the list. If not set, the current zoom level is preserved.
visible
boolean
default:"true"
Initial visibility of the marker.
tooltip
string | object
Tooltip shown when hovering (or clicking) the marker. Pass a string for a simple tooltip or an object to configure position, class, and trigger.
// Simple
tooltip: 'This is a marker'

// Custom position
tooltip: {
    content: 'This is a marker',
    position: 'bottom left',
}

// Click trigger with custom class
tooltip: {
    content: 'This is a marker',
    className: 'custom-tooltip',
    trigger: 'click',
}
Accepted positions: combinations of top, center, bottom and left, center, right. Triggers: hover, click.
content
string
HTML content displayed in the side panel when the marker is clicked.
listContent
string
Name shown in the markers list. Falls back to the tooltip content if not set.
hideList
boolean
default:"false"
Hide this marker from the markers list.
autoplay
boolean
default:"true"
Autoplay for videoLayer markers.
data
any
Arbitrary data attached to the marker, accessible in event handlers.

Methods

addMarker(properties)

Adds a new marker to the viewer.
markersPlugin.addMarker({
    id: 'new-marker',
    position: { yaw: '45deg', pitch: '0deg' },
    image: 'assets/pin-red.png',
    size: { width: 32, height: 32 },
});

updateMarker(properties)

Updates a marker with new properties. The marker type cannot be changed.
markersPlugin.updateMarker({
    id: 'existing-marker',
    image: 'assets/pin-blue.png',
});

removeMarker(id) / removeMarkers(ids)

Removes one or more markers by ID.

setMarkers(properties[])

Replaces all markers with a new set.

clearMarkers()

Removes all markers.

getMarker(id): Marker

Returns a marker by ID.

getCurrentMarker(): Marker

Returns the last marker clicked by the user.

gotoMarker(id, speed?): Promise

Animates the view to face a specific marker. Default speed is 8rpm; pass 0 for an immediate jump.
markersPlugin.gotoMarker('marker-1', '4rpm')
    .then(() => { /* animation complete */ });

hideMarker(id) / showMarker(id) / toggleMarker(id)

Changes the visibility of a single marker.

showMarkerTooltip(id) / hideMarkerTooltip(id)

Forces a marker’s tooltip to be visible or hidden.

showAllTooltips() / hideAllTooltips() / toggleAllTooltips()

Controls the visibility of all tooltips at once.

Events

select-marker(marker, doubleClick, rightClick)

Fired when the user clicks a marker.
markersPlugin.addEventListener('select-marker', ({ marker }) => {
    console.log(`Clicked on marker ${marker.id}`);
});

unselect-marker(marker)

Fired when a previously selected marker is deselected (user clicks elsewhere).

marker-visibility(marker, visible)

Fired when a marker’s visibility changes.
markersPlugin.addEventListener('marker-visibility', ({ marker, visible }) => {
    console.log(`Marker ${marker.id} is ${visible ? 'visible' : 'hidden'}`);
});

enter-marker(marker) / leave-marker(marker)

Fired when the cursor enters or leaves a marker. This plugin adds two buttons to the default navbar:
  • markers — toggles visibility of all markers
  • markersList — opens the markers list in the side panel
If you use a custom navbar, add these button identifiers to your navbar configuration manually.

Build docs developers (and LLMs) love