This example uses a real place, real indoor geometry, a real Leaflet
base map, and real photographs. It combines 135 named indoor spaces at
the Louvre Museum in Paris from a dated OpenStreetMap snapshot with five
Wikimedia Commons photographs associated with three distinct rooms on
levels 0 and 1.
The example is intended to demonstrate the software, not to replace the Louvre’s official visitor, accessibility, evacuation, or safety information. OpenStreetMap is maintained by contributors and indoor details can change.
Inspect the real room data
The bundled GeoJSON uses EPSG:4326 coordinates. Its 135 polygons
cover three OpenStreetMap levels and retain the source way identifiers
needed for traceability. The source snapshot is bundled in
data-raw/, so rebuilding the example does not silently
replace the plan with newer community edits.
room_file <- system.file(
"examples", "real", "louvre-rooms.geojson",
package = "leaflet.indoor"
)
louvre_rooms <- st_read(room_file, quiet = TRUE)
table(louvre_rooms$level)
#>
#> -2 0 1
#> 8 51 76
head(st_drop_geometry(louvre_rooms)[c("feature_id", "level", "name")])
#> feature_id level name
#> 1 osm-way-451560039 -2 Amis du Louvre - espace membres
#> 2 osm-way-376694360 -2 Arts de l'Islam - de 1000 à 1800
#> 3 osm-way-376694363 -2 Arts de l'Islam - de 1000 à 1800
#> 4 osm-way-451560034 -2 Auditorium
#> 5 osm-way-457641196 -2 Expositions temporaires
#> 6 osm-way-367772251 -2 Hall NapoléonThe mapped spaces include the Hall Napoléon, the Salle de la Vénus de Milo, the Salle des Caryatides, the Galerie d’Apollon, and the Grande Galerie. The room names and geometries are those recorded in the cited OpenStreetMap ways, not manually invented coordinates.
Associate photographs with a room
Use one catalogue row per image. Repeating a room identifier produces a carousel in row order. This catalogue associates two photographs with the Salle des Caryatides, one with the Salle de la Vénus de Milo, and two with the Galerie d’Apollon.
photo_directory <- system.file(
"examples", "real", "photos",
package = "leaflet.indoor"
)
louvre_photos <- indoorPhotoCatalog(
layerId = c(
rep("osm-way-394887893", 2),
"osm-way-453817508",
rep("osm-way-367790015", 2)
),
src = file.path(photo_directory, c(
"louvre-caryatides-main.jpg",
"louvre-caryatides-reopening.jpg",
"louvre-venus-room.jpg",
"louvre-apollon-main.jpg",
"louvre-apollon-ceiling.jpg"
)),
caption = c(
paste(
"Salle des Caryatides, photographed in 2024.",
"Photo: Wilfredor, CC0 1.0, via Wikimedia Commons."
),
paste(
"Salle des Caryatides shortly after the Louvre reopened in 2021.",
"Photo: Tangopaso, public domain, via Wikimedia Commons."
),
paste(
"Salle de la Vénus de Milo, photographed in 2016.",
"Photo: Shonagon, CC0 1.0, via Wikimedia Commons."
),
paste(
"Galerie d'Apollon, photographed in 2024.",
"Photo: Wilfredor, CC0 1.0, via Wikimedia Commons."
),
paste(
"Ceiling of the Galerie d'Apollon, photographed in 2016.",
"Photo: Gary Todd, CC0 1.0, via Wikimedia Commons."
)
),
alt = c(
"Wide interior view of the Salle des Caryatides at the Louvre",
"Interior of the Salle des Caryatides with few visitors",
"Salle de la Vénus de Milo with the sculpture centered in the room",
"Long interior view of the decorated Galerie d'Apollon",
"Painted and gilded ceiling of the Galerie d'Apollon"
)
)
data.frame(
layerId = louvre_photos$layerId,
caption = louvre_photos$caption
)
#> layerId
#> 1 osm-way-394887893
#> 2 osm-way-394887893
#> 3 osm-way-453817508
#> 4 osm-way-367790015
#> 5 osm-way-367790015
#> caption
#> 1 Salle des Caryatides, photographed in 2024. Photo: Wilfredor, CC0 1.0, via Wikimedia Commons.
#> 2 Salle des Caryatides shortly after the Louvre reopened in 2021. Photo: Tangopaso, public domain, via Wikimedia Commons.
#> 3 Salle de la Vénus de Milo, photographed in 2016. Photo: Shonagon, CC0 1.0, via Wikimedia Commons.
#> 4 Galerie d'Apollon, photographed in 2024. Photo: Wilfredor, CC0 1.0, via Wikimedia Commons.
#> 5 Ceiling of the Galerie d'Apollon, photographed in 2016. Photo: Gary Todd, CC0 1.0, via Wikimedia Commons.Existing local images are embedded as image data URIs. The interactive map is therefore portable even though the source files are local package assets.
Explore the map
Red polygons identify rooms with photographs. On level
0, click the Salle des Caryatides to see a two-photo
carousel or the Salle de la Vénus de Milo to see its room photograph.
Then select level 1 and click the Galerie d’Apollon for a
second two-photo carousel. Use Previous and Next to change photos, and
Enlarge to open the current image with its matching caption. Rooms
without catalogue rows retain their ordinary popup.
photo_room_names <- c(
"Salle des Caryatides",
"Salle de la Vénus de Milo",
"Galerie d'Apollon"
)
louvre_rooms$fill <- ifelse(
louvre_rooms$name %in% photo_room_names,
"#c43c2e",
c(`-2` = "#6b7280", `0` = "#2f7d65", `1` = "#3568a8")[louvre_rooms$level]
)
leaflet(louvre_rooms, height = 600) |>
addTiles() |>
addIndoor(
level = "level",
level_order = c("-2", "0", "1"),
initial_level = "0",
layerId = ~feature_id,
photos = louvre_photos,
comments = read.csv(
system.file("examples", "real", "louvre-comments.csv", package = "leaflet.indoor"),
stringsAsFactors = FALSE,
fileEncoding = "UTF-8"
),
commentOptions = indoorCommentOptions(
icon = "quote", marker_label = "Read visitor accounts",
popup_label = "Visitor accounts", source_label = "Read the original account"
),
label = ~name,
popup = ~paste0(name, ". Level ", level, ". ", description),
style = list(
color = "#17324d",
weight = 2,
fillColor = ~fill,
fillOpacity = 0.72
),
popupOptions = popupOptions(keepInView = TRUE)
) |>
addIndoorControl(
position = "bottomright",
options = indoorControlOptions(title = "Louvre level")
)This rendered map exercises the geographic path of
addIndoor(): real longitude and latitude coordinates are
displayed over live OpenStreetMap tiles, exactly one floor is active,
and photographs are joined through the same stable identifiers used by
the vector features.
Purple quotation icons open published visitor accounts for the Vénus de Milo, the Salle des États, and the Galerie d’Apollon. Each entry includes attribution, its publication date, and a source link. Click a room away from its icon to open its ordinary popup or photographs. See the room-comments article for provenance and customization.
Data and image provenance
The source extract was downloaded on 2026-09-08 from the official
OpenStreetMap API. The example selects all 135 named indoor rooms or
areas on levels -2, 0, and 1
within that extract. OpenStreetMap data is copyright OpenStreetMap
contributors and licensed under the ODbL 1.0. See
the OpenStreetMap
copyright page.
The first Salle des Caryatides photograph is by Wilfredor and is available under CC0 1.0 on Wikimedia Commons. The second Salle des Caryatides photograph is by Tangopaso, who dedicated it to the public domain, and is also available on Wikimedia Commons.
The Salle de la Vénus de Milo photograph is by Shonagon and is available under CC0 1.0 on Wikimedia Commons. The two Galerie d’Apollon photographs are by Wilfredor and Gary Todd, respectively, and are both available under CC0 1.0 on Wikimedia Commons and Wikimedia Commons. The package includes full source URLs and a detailed attribution file with all five example assets.
Adapt the pattern
For another building, provide an sf object with stable
room identifiers and a level column, then build the same
one-row-per-photo association. The optional alt column
should describe the image for people who cannot see it. Captions and
alternative text are treated as plain text.
All carousel labels can be translated:
indoorPhotoOptions(
previous_label = "Précédent",
next_label = "Suivant",
enlarge_label = "Agrandir",
close_label = "Fermer",
carousel_label = "Photos de la pièce",
dialog_label = "Photo agrandie de la pièce",
counter_label = "Photo {current} sur {total}",
unavailable_label = "Image indisponible"
)The fully offline synthetic example remains available through
system.file("examples", "photo-carousel.R", package = "leaflet.indoor")
for tests and environments where live map tiles are unavailable.