Skip to content

Commit

Permalink
buldings working
Browse files Browse the repository at this point in the history
  • Loading branch information
trafficonese committed Sep 1, 2024
1 parent a1fdf17 commit bb8cb1a
Show file tree
Hide file tree
Showing 14 changed files with 466 additions and 2,550 deletions.
4 changes: 3 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ Imports:
magrittr
Suggests:
sf,
sp
sp,
testthat (>= 3.0.0)
URL: https://github.com/trafficonese/leaflet.extras2
BugReports: https://github.com/trafficonese/leaflet.extras2/issues
RoxygenNote: 7.3.1
Config/testthat/edition: 3
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export(removeReachability)
export(removeSidebar)
export(removeSidebyside)
export(removeVelocity)
export(setBuildingData)
export(setBuildingStyle)
export(showHexbin)
export(sidebar_pane)
export(sidebar_tabs)
Expand Down
84 changes: 60 additions & 24 deletions R/buildings.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,85 @@ buildingsDependency <- function() {
src = system.file("htmlwidgets/lfx-building", package = "leaflet.extras2"),
stylesheet = "osm-buildings.css",
script = c(
# "osm-buildings.js",
"OSMBuildings.js",
"osm-buildings.js",
"osm-buildings-bindings.js")
)
)
}

#' Add OSM-Buildings
#' Add OSM-Buildings to a Leaflet Map
#'
#' @param map A map widget object created from \code{\link[leaflet]{leaflet}}
#' @param options List of further options. See \code{\link{hexbinOptions}}
#' This function adds 2.5D buildings to a Leaflet map using the OSM Buildings plugin.
#'
#' @note Out of the box a legend image is only available for Pressure,
#' Precipitation Classic, Clouds Classic, Rain Classic, Snow, Temperature and
#' Wind Speed.
#' @seealso https://osmbuildings.org/documentation/viewer/
#' @param map A map widget object created from \code{\link[leaflet]{leaflet}}.
#' @param buildingURL The URL template for the building data. Default is the OSM Buildings tile server: \cr
#' \code{"https://{s}.data.osmbuildings.org/0.2/59fcc2e8/tile/{z}/{x}/{y}.json"}.
#' @param group The name of the group the buildings will be added to.
#' @param eachFn A JavaScript function (using \code{\link[htmlwidgets]{JS}}) that will be called for each building feature. Use this to apply custom logic to each feature.
#' @param clickFn A JavaScript function (using \code{\link[htmlwidgets]{JS}}) that will be called when a building is clicked. Use this to handle click events on buildings.
#' @param data A GeoJSON object containing Polygon features representing the buildings. The properties of these polygons can include attributes like \code{height}, \code{color}, \code{roofColor}, and others as specified in the OSM Buildings documentation.
#'
#' @details
#' The `data` parameter allows you to provide custom building data as a GeoJSON object. The following properties can be used within the GeoJSON:
#' \itemize{
#' \item \strong{height}
#' \item \strong{minHeight}
#' \item \strong{color/wallColor}
#' \item \strong{material}
#' \item \strong{roofColor}
#' \item \strong{roofMaterial}
#' \item \strong{shape}
#' \item \strong{roofShape}
#' \item \strong{roofHeight}
#' }
#'
#' See the OSM Wiki: \href{https://wiki.openstreetmap.org/wiki/Simple_3D_Buildings}
#'
#' @seealso \url{https://github.com/kekscom/osmbuildings/} for more details on the OSM Buildings plugin and available properties.
#' @family OSM-Buildings Plugin
#' @export
addBuildings <- function(
map, layerId = NULL, group = NULL, opacity = 0.5,
attribution = '© Map tiles <a href="https://mapbox.com">Mapbox</a>') {

# if (is.null(apikey)) {
# apikey <- Sys.getenv("MAPBOX")
# if (apikey == "") {
# stop("You must either pass an `apikey` directly or save it as ",
# "system variable under `MAPBOX`.")
# }
# }
map,
buildingURL = "https://{s}.data.osmbuildings.org/0.2/59fcc2e8/tile/{z}/{x}/{y}.json",
group = NULL,
eachFn = NULL, clickFn = NULL, data = NULL) {

map$dependencies <- c(map$dependencies, buildingsDependency())

invokeMethod(map, getMapData(map), "addBuilding", layerId, group,
opacity, attribution)
invokeMethod(map, getMapData(map), "addBuilding",
buildingURL, group,
eachFn, clickFn, data)
}


#' Update the Shadows OSM-Buildings with a POSIXct timestamp
#'
#' @param map A map widget object created from \code{\link[leaflet]{leaflet}}
#' @seealso https://osmbuildings.org/documentation/viewer/
#' @inheritParams addBuildings
#' @param time a timestamp that can be converted to POSIXct
#' @family OSM-Buildings Plugin
#' @export
updateBuildingTime <- function(map, time) {
invokeMethod(map, NULL, "updateBuildingTime", as.POSIXct(time))
invokeMethod(map, NULL, "updateBuildingTime", time)
}

#' Update the OSM-Buildings Style
#'
#' @inheritParams addBuildings
#' @param style A named list of styles
#' @family OSM-Buildings Plugin
#' @export
setBuildingStyle <- function(map, style = list(color = "#ffcc00",
wallColor = "#ffcc00",
roofColor = "orange",
shadows = TRUE)) {
invokeMethod(map, NULL, "setBuildingStyle", style)
}

#' Update the OSM-Buildings Data
#'
#' @inheritParams addBuildings
#' @family OSM-Buildings Plugin
#' @export
setBuildingData <- function(map, data) {
invokeMethod(map, NULL, "setBuildingData", data)
}
1 change: 1 addition & 0 deletions inst/examples/Buildings_mini.geojson

Large diffs are not rendered by default.

100 changes: 86 additions & 14 deletions inst/examples/buildings_app.R
Original file line number Diff line number Diff line change
@@ -1,32 +1,104 @@
library(shiny)
library(leaflet)
library(yyjsonr)
library(sf)
library(leaflet.extras2)
options("shiny.autoreload" = TRUE)

cols <- c("green","orange","red","pink","yellow","blue","lightblue")
darkcols <- c("lightgray","gray","#c49071","#876302","#443408")

## Custom GeoJSON ###########
## Get a Sample Building Dataset from
# https://hub.arcgis.com/datasets/IthacaNY::buildings/explore?location=42.432557%2C-76.486649%2C13.42
geojson <- yyjsonr::read_geojson_file("Buildings_mini.geojson")
geojson$height= sample(seq(50,100,5), nrow(geojson), replace = TRUE)
geojson$color= sample(cols, nrow(geojson), replace = TRUE)
geojson$wallColor= sample(cols, nrow(geojson), replace = TRUE)
geojson$roofColor= sample(darkcols, nrow(geojson), replace = TRUE)
geojson$shape= sample(c("cylinder","sphere",""), nrow(geojson), replace = TRUE)
geojson$roofHeight= geojson$height + sample(seq(1,10,1), nrow(geojson), replace = TRUE)
geojson$roofShape= sample(c("dome","pyramidal", "butterfly","gabled","half-hipped",
"gambrel","onion"), nrow(geojson), replace = TRUE)
geojson <- yyjsonr::write_geojson_str(geojson)
class(geojson) <- "json"

## UI ###########
ui <- fluidPage(
leafletOutput("map", height = "700px"),
dateInput("date", "Date"),
sliderInput("time", "Time", 0, max = 24, value = 4, step = 1)
# actionButton("update", "Update Date")
titlePanel("OSM Buildings (2.5D)"),
sidebarLayout(
sidebarPanel(
h4("Use the OSM Buildings or a Custom GeoJSON")
, selectInput("src", label = "Data Source", choices = c("OSM", "GeoJSON"))
, h4("Change the Date and Time-Slider to Adapt the Shadow")
, dateInput("date", "Date")
, sliderInput("time", "Time", 7, max =20, value = 11, step = 1)
, h4("Change the Style and the Data")
, actionButton("style", "Update Style")
, actionButton("data", "Update Data")
),
mainPanel(
leafletOutput("map", height = "700px")
),
fluid = TRUE
)
)

## SERVER ###########
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>%
# addTiles() %>%
# addProviderTiles("CartoDB.DarkMatter") %>%
addBuildings() %>%
addMarkers(data = breweries91) %>%
setView(lng = 13.40438, lat = 52.51836, zoom = 16)
m <- leaflet() %>%
addProviderTiles("CartoDB")

if (input$src == "OSM") {
m <- m %>%
addBuildings(
group = "Buildings"
# , eachFn = leaflet::JS("function(e) { console.log('each feature:', e); }")
# , clickFn = leaflet::JS("function(e) { console.log('clicked:', e); }")
)
} else {
m <- m %>%
addBuildings(
group = "Buildings"
, buildingURL = NULL
, data = geojson
)
}

m %>%
addLayersControl(overlayGroups = "Buildings") %>%
setView(lng = -76.51, lat = 42.433, zoom = 15)
})
observe({
# observeEvent(input$update, {
# browser()
date <- input$date
time <- formatC(input$time, width = 2, format = "d", flag = "0")
updatetime <- paste0(date, " ", time, ":00:00")
updatetime <- paste0(input$date, " ", time, ":00:00")
leafletProxy("map") %>%
updateBuildingTime(time = as.POSIXct(updatetime))
})
observeEvent(input$style, {
leafletProxy("map") %>%
setBuildingStyle(style = list(color = sample(cols, 1),
wallColor = sample(cols, 1),
roofColor = sample(cols, 1),
roofShape = sample(c("dome","pyramidal", "butterfly","gabled","half-hipped",
"gambrel","onion"), 1),
shadows = sample(c(TRUE, FALSE), 1)))
})
observeEvent(input$data, {
geojson <- yyjsonr::read_geojson_file("Buildings_mini.geojson")
filtered <- geojson[sample(1:nrow(geojson), 10, F),]
filtered$height= sample(seq(50,140,5), nrow(filtered), replace = TRUE)
filtered$color= sample(cols, nrow(filtered), replace = TRUE)
filtered$wallColor= sample(cols, nrow(filtered), replace = TRUE)
filtered$roofColor= sample(cols, nrow(filtered), replace = TRUE)
filtered <- yyjsonr::write_geojson_str(filtered)
class(filtered) <- "json"

leafletProxy("map") %>%
setBuildingData(data = filtered)
})
}

shinyApp(ui, server)

Loading

0 comments on commit bb8cb1a

Please sign in to comment.