I have created an application in Shiny
which allows for selecting a place and then displays a datatable with information and a marker at the corresponding position in the map. The marker is set in the map but not in the minimap. I would like to extend my app such that the marker is also added in the minimap. How to do this?
This is the code of the application and its libraries.
library(shiny)
library(leaflet)
library(leaflet.extras)
library(shinyjs)
library(tidyverse)
leafletMiniMapDependencies <- function() {
list(
htmltools::htmlDependency(
"leaflet-minimap",
"3.3.1",
"htmlwidgets/plugins/Leaflet-MiniMap",
package = "leaflet",
script = c("Control.MiniMap.min.js", "Minimap-binding.js"),
stylesheet = c("Control.MiniMap.min.css")
)
)
}
addMiniMap <- function(
map,
position = "bottomleft",
width = 300,
height = 225,
collapsedWidth = 19,
collapsedHeight = 19,
zoomLevelOffset = -5,
zoomLevelFixed = 6,
centerFixed = c(28, -15.5),
zoomAnimation = FALSE,
toggleDisplay = T,
autoToggleDisplay = FALSE,
minimized = FALSE,
aimingRectOptions = list(color = "rgba(0,0,0,0)", weight = 1, clickable = FALSE),
shadowRectOptions = list(color = "#000000", weight = 1, clickable = FALSE,
opacity = 0, fillOpacity = 0),
strings = list(hideText = "Hide MiniMap", showText = "Show MiniMap"),
tiles = NULL,
mapOptions = list(minZoom = 6, maxZoom = 6)
) {
# determin tiles to use
tilesURL <- NULL
tilesProvider <- NULL
if (!is.null(tiles)) {
if (tiles %in% providers) {
map$dependencies <- c(map$dependencies, leafletProviderDependencies())
tilesProvider <- tiles
} else {
tilesURL <- tiles
}
}
map$dependencies <- c(map$dependencies, leafletMiniMapDependencies())
invokeMethod(
map
, getMapData(map)
, "addMiniMap"
, tilesURL
, tilesProvider
, position
, width
, height
, collapsedWidth
, collapsedHeight
, zoomLevelOffset
, zoomLevelFixed
, centerFixed
, zoomAnimation
, toggleDisplay
, autoToggleDisplay
, minimized
, aimingRectOptions
, shadowRectOptions
, strings
, mapOptions
)
}
topologia <- data.frame(
etiqueta = c("El Hierro", "Fuerteventura", "Gran Canaria", "La Palma", "Lanzarote", "Tenerife"),
longitud = c(-18.038165, -14.004885, -15.606239, -17.857377, -13.636218, -16.621481),
latitud = c(27.743606, 28.400363, 27.958157, 28.655223, 29.039468, 28.293378),
geocode = c("ES703", "ES704", "ES705", "ES707", "ES708", "ES709"),
valor = 1:6
)
topologia <- topologia %>%
mutate(
longitud = as.numeric(gsub("\\.", "", longitud)) / 10^6,
latitud = as.numeric(gsub("\\.", "", latitud)) / 10^6
)
# Define UI for application
ui <- fluidPage(
tags$head(
tags$style(HTML("
body{
.leaflet-control-search{
position: absolute !important;
left: 50% !important;
transform: translateX(-50%) !important;
margin-left: 0 !important;
}
.leaflet-top.leaflet-left{
width: 100%;
}
"))
),
useShinyjs(),
titlePanel("Mapa"),
sidebarPanel(
selectInput("provincia_seleccionada", "Provincia", choices = unique(topologia$etiqueta)),
actionButton("consultar", "Consulta")
),
column(width = 12, leafletOutput("map", height = "600px")),
column(width = 12, dataTableOutput("data"))
)
# Define server logic
server <- function(input, output, session) {
# processing with click of consultar data
topologia_consulta <- eventReactive(input$consultar, {
topologia %>% filter(etiqueta %in% input$provincia_seleccionada) %>%
filter(!is.na(latitud) & !is.na(longitud))
})
# show data in datatable
output$data <- renderDataTable(topologia_consulta())
# Render the map
output$map <- renderLeaflet({
leaflet() %>%
leaflet(options = leafletOptions(minZoom = 5)) %>%
addTiles(options = tileOptions(updateWhenIdle = TRUE, updateWhenZooming = FALSE)) %>%
addFullscreenControl() %>%
addProviderTiles(providers$OpenStreetMap) %>%
setView(lat = 40.416775, lng = -3.703790, zoom = 6) %>%
addMiniMap() %>%
addEasyButton(easyButton(
icon = "fa-crosshairs", title = "Locate Me",
onClick = JS("function(btn, map){ map.locate({setView: true}); }")
)) %>%
# addSearchOSM(options = searchOptions(collapsed = FALSE, autoCollapse = TRUE, minLength = 2)) %>%
leaflet.extras::addSearchOSM(options = searchOptions(collapsed = F)) %>%
addEasyButton(easyButton(states = list(
easyButtonState(
stateName = "Canarias",
icon = '<strong>Ir a Islas Canarias</strong>',
title = "Ir a Islas Canarias",
onClick = JS("
function(btn, map) {
map.flyTo(L.latLng(28, -15.5), 7);
btn.state('Peninsula');
}")
),
easyButtonState(
stateName = "Peninsula",
icon = '<strong>Ir a Península</strong>',
title = "Ir a Península",
onClick = JS("
function(btn, map) {
map.flyTo(L.latLng(40.416775, -3.703790), 6);
btn.state('Canarias');
}")
)), id = 'botonCanarias', position = 'bottomleft')) %>%
htmlwidgets::onRender(paste0("
function(el, t) {
var myMap = this;
$('#searchtext25').attr('placeholder', 'Buscar localización...');
$('#searchtext25').on('input', function(){
if($(this).val() === '')
$(\"path.leaflet-interactive[stroke='#3388ff'][stroke-linecap='round']\").hide();
});
$('#map ul.search-tooltip').on('mouseup', 'li', function(){
$(\"path.leaflet-interactive[stroke='#3388ff'][stroke-linecap='round']\").show();
});
$('#map a.search-cancel').on('click', function(){
$(\"path.leaflet-interactive[stroke='#3388ff'][stroke-linecap='round']\").hide();
});
}")) %>%
addLayersControl(
overlayGroups = c("Pintar"),
options = layersControlOptions(collapsed = TRUE)
)
})
# When click in consultar bottom show the map
observeEvent(input$consultar, {
mapProxy <- leafletProxy("map")
mapProxy %>%
clearGroup("Pintar") %>%
addAwesomeMarkers(data = topologia_consulta(),
lng = ~topologia_consulta()$longitud,
lat = ~topologia_consulta()$latitud,
group = "Pintar",
popup = ~paste0(
"<b>Isla:</b> ", topologia_consulta()$etiqueta, "</b><br/>",
"<b>GeoCode:</b> ", topologia_consulta()$geocode, "</b><br/>",
"<b>Valor:</b> ", topologia_consulta()$valor, "<br/>"
)
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
You can use the following event handler inside the htmlwidgets::onRender()
:
myMap.on('layeradd', // if we add a layer on the original map
function(e) {
if (e.layer._eventParents != null) {
var layers = new L.LayerGroup(
// set a new layer group consisting out of the initial layer
// and a marker at the position of the one from the map
[initialLayer, L.marker(e.layer._latlng)]
);
// assign the layergroup to the minimap
myMap.minimap.changeLayer(layers);
})
library(shiny)
library(leaflet)
library(leaflet.extras)
library(shinyjs)
library(tidyverse)
leafletMiniMapDependencies <- function() {
list(
htmltools::htmlDependency(
"leaflet-minimap",
"3.3.1",
"htmlwidgets/plugins/Leaflet-MiniMap",
package = "leaflet",
script = c("Control.MiniMap.min.js", "Minimap-binding.js"),
stylesheet = c("Control.MiniMap.min.css")
)
)
}
addMiniMap <- function(
map,
position = "bottomleft",
width = 300,
height = 225,
collapsedWidth = 19,
collapsedHeight = 19,
zoomLevelOffset = -5,
zoomLevelFixed = 6,
centerFixed = c(28, -15.5),
zoomAnimation = FALSE,
toggleDisplay = T,
autoToggleDisplay = FALSE,
minimized = FALSE,
aimingRectOptions = list(color = "rgba(0,0,0,0)", weight = 1, clickable = FALSE),
shadowRectOptions = list(color = "#000000", weight = 1, clickable = FALSE,
opacity = 0, fillOpacity = 0),
strings = list(hideText = "Hide MiniMap", showText = "Show MiniMap"),
tiles = NULL,
mapOptions = list(minZoom = 6, maxZoom = 6)
) {
# determin tiles to use
tilesURL <- NULL
tilesProvider <- NULL
if (!is.null(tiles)) {
if (tiles %in% providers) {
map$dependencies <- c(map$dependencies, leafletProviderDependencies())
tilesProvider <- tiles
} else {
tilesURL <- tiles
}
}
map$dependencies <- c(map$dependencies, leafletMiniMapDependencies())
invokeMethod(
map
, getMapData(map)
, "addMiniMap"
, tilesURL
, tilesProvider
, position
, width
, height
, collapsedWidth
, collapsedHeight
, zoomLevelOffset
, zoomLevelFixed
, centerFixed
, zoomAnimation
, toggleDisplay
, autoToggleDisplay
, minimized
, aimingRectOptions
, shadowRectOptions
, strings
, mapOptions
)
}
topologia <- data.frame(
etiqueta = c("El Hierro", "Fuerteventura", "Gran Canaria", "La Palma", "Lanzarote", "Tenerife"),
longitud = c(-18.038165, -14.004885, -15.606239, -17.857377, -13.636218, -16.621481),
latitud = c(27.743606, 28.400363, 27.958157, 28.655223, 29.039468, 28.293378),
geocode = c("ES703", "ES704", "ES705", "ES707", "ES708", "ES709"),
valor = 1:6
)
topologia <- topologia %>%
mutate(
longitud = as.numeric(gsub("\\.", "", longitud)) / 10^6,
latitud = as.numeric(gsub("\\.", "", latitud)) / 10^6
)
# Define UI for application
ui <- fluidPage(
tags$head(
tags$style(HTML("
body{
.leaflet-control-search{
position: absolute !important;
left: 50% !important;
transform: translateX(-50%) !important;
margin-left: 0 !important;
}
.leaflet-top.leaflet-left{
width: 100%;
}
"))
),
useShinyjs(),
titlePanel("Mapa"),
sidebarPanel(
selectInput("provincia_seleccionada", "Provincia", choices = unique(topologia$etiqueta)),
actionButton("consultar", "Consulta")
),
column(width = 12, leafletOutput("map", height = "600px")),
column(width = 12, dataTableOutput("data"))
)
# Define server logic
server <- function(input, output, session) {
# processing with click of consultar data
topologia_consulta <- eventReactive(input$consultar, {
topologia %>% filter(etiqueta %in% input$provincia_seleccionada) %>%
filter(!is.na(latitud) & !is.na(longitud))
})
# show data in datatable
output$data <- renderDataTable(topologia_consulta())
# Render the map
output$map <- renderLeaflet({
leaflet() %>%
leaflet(options = leafletOptions(minZoom = 5)) %>%
addTiles(options = tileOptions(updateWhenIdle = TRUE, updateWhenZooming = FALSE)) %>%
addFullscreenControl() %>%
addProviderTiles(providers$OpenStreetMap) %>%
setView(lat = 40.416775, lng = -3.703790, zoom = 6) %>%
addMiniMap() %>%
addEasyButton(easyButton(
icon = "fa-crosshairs", title = "Locate Me",
onClick = JS("function(btn, map){ map.locate({setView: true}); }")
)) %>%
# addSearchOSM(options = searchOptions(collapsed = FALSE, autoCollapse = TRUE, minLength = 2)) %>%
leaflet.extras::addSearchOSM(options = searchOptions(collapsed = F)) %>%
addEasyButton(easyButton(states = list(
easyButtonState(
stateName = "Canarias",
icon = '<strong>Ir a Islas Canarias</strong>',
title = "Ir a Islas Canarias",
onClick = JS("
function(btn, map) {
map.flyTo(L.latLng(28, -15.5), 7);
btn.state('Peninsula');
}")
),
easyButtonState(
stateName = "Peninsula",
icon = '<strong>Ir a Península</strong>',
title = "Ir a Península",
onClick = JS("
function(btn, map) {
map.flyTo(L.latLng(40.416775, -3.703790), 6);
btn.state('Canarias');
}")
)), id = 'botonCanarias', position = 'bottomleft')) %>%
htmlwidgets::onRender(paste0("
function(el, t) {
var myMap = this;
$('#searchtext25').attr('placeholder', 'Buscar localización...');
$('#searchtext25').on('input', function(){
if($(this).val() === '')
$(\"path.leaflet-interactive[stroke='#3388ff'][stroke-linecap='round']\").hide();
});
$('#map ul.search-tooltip').on('mouseup', 'li', function(){
$(\"path.leaflet-interactive[stroke='#3388ff'][stroke-linecap='round']\").show();
});
$('#map a.search-cancel').on('click', function(){
$(\"path.leaflet-interactive[stroke='#3388ff'][stroke-linecap='round']\").hide();
});
// save initial layer (so that we can remove older markers)
var initialLayer = myMap.minimap._layer;
myMap.on('layeradd', // if we add a layer on the original map
function (e) {
if (e.layer._eventParents != null) {
var layers = new L.LayerGroup(
// set a new layer group consisting out of the initial layer
// and a marker at the position of the one from the map
[initialLayer, L.marker(e.layer._latlng)]
);
// assign the layergroup to the minimap
myMap.minimap.changeLayer(layers);
}
})
}")) %>%
addLayersControl(
overlayGroups = c("Pintar"),
options = layersControlOptions(collapsed = TRUE)
)
})
# When click in consultar bottom show the map
observeEvent(input$consultar, {
mapProxy <- leafletProxy("map")
mapProxy %>%
clearGroup("Pintar") %>%
addAwesomeMarkers(data = topologia_consulta(),
lng = ~topologia_consulta()$longitud,
lat = ~topologia_consulta()$latitud,
group = "Pintar",
popup = ~paste0(
"<b>Isla:</b> ", topologia_consulta()$etiqueta, "</b><br/>",
"<b>GeoCode:</b> ", topologia_consulta()$geocode, "</b><br/>",
"<b>Valor:</b> ", topologia_consulta()$valor, "<br/>"
)
)
})
}
# Run the application
shinyApp(ui = ui, server = server)