У меня есть блестящее приложение, работающее здесь. Он отображает около 12 тысяч квартир и комнат для сдачи в аренду на интерактивной карте-буклете и добавляет на карту маркер на основе адреса, вводимого пользователем. Вот код. Извините за то, что это плохо документировано.
Есть два разных объекта фрейма данных: один для квартир (df.apt
), а другой - для комнат (df.quartos
).
Однако из-за большого количества данных, загружаемых приложением, оно работает немного медленнее. Я хочу добавить ресурс, который будет отображать данные только после того, как пользователь введет адрес, а также выберет диапазон близости (например, показать только квартиры в пределах 10 км от введенного адреса). Как мне это сделать?
library(leaflet)
library(shiny)
library(ggmap)
source("post4-prepararshiny.R") #loads data and helper functions
ui = bootstrapPage(
div(class = "outer",
tags$head(
# Include our custom CSS
includeCSS("styles.css"),
includeScript("gomap.js")
),
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("mymap", width = "100%", height = "100%"),
absolutePanel(id = "controls",# class = "panel panel-default",
fixed = TRUE,
draggable = TRUE,
top = 60, left = "auto", right = 20, bottom = "auto",
width = 330, height = "auto",
h2("Buscador OLX"),
textInput(inputId = "userlocation",
label = "Digite um endereço\n com pelo menos rua, número, bairro e cidade",
value = ""),
helpText("Exemplo: Rua Dias da Rocha, 85 - Copacabana, Rio de Janeiro - RJ"),
sliderInput(inputId = "distancia", label = "Escolha a distância em km:",
min = 0, max = 30, value = 15),
actionButton("go", "Buscar"),
helpText("Encontre imóveis para alugar perto de onde você quiser!"),
helpText("Cada ponto no mapa representa um imóvel para alugar.",
"A cor de um ponto é determinada pelo valor do aluguel.",
"Clique em um ponto para ter mais informações sobre o imóvel."),
helpText("Mais informações sobre este app em sillasgonzaga.github.io")
)
),
tags$div(id="cite",
'Dados extraídos do OLX em 12/11/2016.', ' Contato: sillasgonzaga.github.io'
)
)
server.R
server = function(input, output, session){
#browser()
output$mymap <- renderLeaflet({
map <- leaflet() %>%
addTiles() %>%
addProviderTiles("OpenStreetMap.BlackAndWhite") %>%
# coordenadas de um ponto em específico
addMarkers(lat = -22.911872, lng = -43.230184,
popup = "Estádio do Maracanã! <br> Apenas um exemplo!") %>%
# plotar apartamentos
addCircleMarkers(data = df.apt,
lng = ~lon, lat = ~lat,
color = ~vetorCoresApt(preco),
opacity = 1.5,
popup = textoPopup(df.apt, "apartamento"),
# Definir nome do grupo para ser usado na camada
group = "Apartamentos") %>%
# plotar quartos
addCircleMarkers(data = df.quartos,
lng = ~lon, lat = ~lat,
color = ~vetorCoresQuarto(preco),
opacity = 1.5,
popup = textoPopup(df.quartos, "quarto"),
group = "Quartos") %>%
addLayersControl(
overlayGroups = c("Apartamentos", "Quartos"),
options = layersControlOptions(collapsed = FALSE),
position = "bottomright"
) %>%
addLegend(pal = vetorCoresApt, values = df.apt$preco,
position = "bottomright")
map
})
observeEvent(input$go, {
v <- geocode(input$userlocation)
leafletProxy('mymap', session) %>% addMarkers(lng = v$lon,lat = v$lat)
})
}
Я знаю, что могу использовать функцию geosphere::distm()
для вычисления расстояния между матрицей данных и точкой данных, например:
coord <- matrix(data = c(df.apt$lon, df.apt$lat), ncol = 2)
distance_vector <- distm(x = coord, y = c(lon = -43.183447, lat = -22.913912), fun = distVincentySphere)
# insert vector into data frame
df.apt$distance <- distance_vector
Однако как мне сделать это реактивным способом, который позволит мне изменять столбец distance
каждый раз, когда пользователи нажимают кнопку, и изменять sliderInput()
, который будет использоваться для указания диапазона близости?
P.S .: Извините за код и комментарии на португальском языке.
РЕДАКТИРОВАТЬ: РЕШЕНО
Я смог придумать решение после ответа @HubertL. Вот что я сделал на server.R
:
distance_apt_reactive <- eventReactive(input$go, {
address_latlon <- geocode(input$userlocation)
dist <- distm(x = matrix(data = c(df.apt$lon, df.apt$lat), ncol = 2),
y = c(lon = address_latlon$lon, lat = address_latlon$lat),
fun = distVincentySphere)
dist <- dist/1000
})
apt_reactive <- reactive({df.apt[distance_reactive() < input$distancia,]})
output$mymap <- renderLeaflet({
map <- leaflet() %>%
addTiles() %>%
addProviderTiles("OpenStreetMap.BlackAndWhite") %>%
setView(lng = mean(df.apt$lon), lat = mean(df.apt$lat), zoom = 11) %>%
addLegend(pal = vetorCoresApt, values = df.apt$preco,
position = "bottomright",
layerId = "legend")
map
})
observe({
leafletProxy("mymap") %>%
clearMarkers() %>%
#addMarkers(lng = myadress()$lon, lat = myadress()$lat) %>%
addCircleMarkers(data = apt_reactive(),
lng = ~lon, lat = ~lat,
color = ~vetorCoresQuarto(preco),
opacity = 1.5,
# adicionar popup
popup = textoPopup(apt_reactive(), "apartamento"),
group = "Apartamentos")
})