As a Seminarproject during my bachelorstudies I created an interactive map of Gießen with Quarto, communicating places connected to sustainability.
How I did it
library(crosstalk) # <- main library for static interactive R visualizations
library(leaflet) # for maps
library(dplyr)
library(reactable) # <- main library for static interactive R visualizations
library(DT)
library(htmltools)Since I created my own custom icons I defined helperfunctions to implement these.
Iconheight <- 38
Iconwidth <- 38
myIcons <- iconList(
Garten = makeIcon(iconUrl = "media/1.svg",
iconWidth = Iconwidth,
iconHeight = Iconheight),
Gastronomie = makeIcon(iconUrl = "media/2.svg",
iconWidth = Iconwidth,
iconHeight = Iconheight),
Shop = makeIcon(iconUrl = "media/3.svg",
iconWidth = Iconwidth,
iconHeight = Iconheight),
Teilen = makeIcon(iconUrl = "media/4.svg",
iconWidth = Iconwidth,
iconHeight = Iconheight),
Info = makeIcon(iconUrl = "media/6.svg",
iconWidth = Iconwidth,
iconHeight = Iconheight)
)To make the map easy to update the place-data (title, description, coordinates, type) are stored in a csv file. The shared-data needs to be defined to make the filter possible. It is basically the conenction between the map and the filters.
# load data ----
locations <- read.csv("locations.csv") %>%
mutate(type = factor(type)) %>%
mutate(ID = row_number()) %>%
mutate(popup_content = paste(
'<strong>', name, '</strong><br>',
description, '<br>',
ifelse(url != "", paste('<br><em>Website:</em> ', '<a href="', url, '" target="_blank">', substr(url, 9, nchar(url)), '</a>', '<br>'), ""),
'<br><em>Type:</em> ', type
))
# create shared data for crosstalk
shared_locations <- SharedData$new(locations, key = ~ID) # implement filter ----
bscols(
widths = c(8,4),
HTML("<p></p>"),
filter_select(
id = "location_filter",
label = "Filter Ortstyp",
sharedData = shared_locations,
group = ~type,
allLevels = TRUE,
multiple = TRUE
)
)Finally the main part of the code:
# Plots ----
bscols(
widths = c(8,4),
device = "sm",
## Map ----
leaflet(shared_locations) %>%
addTiles() %>%
setView(lng = 8.6731, lat = 50.5867, zoom = 13) %>%
addMarkers(
lng = ~longitude,
lat = ~latitude,
icon = ~myIcons[as.character(type)],
popup = ~popup_content) %>%
addEasyButton(
easyButton(
icon="fa-map",
title="Standardansicht - Gießen",
onClick=JS("function(btn, map){ map.setView([50.5867, 8.6731], 13);}")
)
),
## Table ----
datatable(shared_locations,
extensions = c(
"Buttons", # add download buttons, etc
"Scroller" # for scrolling down the rows rather than pagination
),
rownames = FALSE, # remove rownames
style = "bootstrap",
class = "compact",
width = "100%",
options = list(
initComplete = JS("function(settings, json) {",
"$(this.api().table().header()).css({'background-color': '#dfd4ae', 'color': '#19486a'});","}"),
dom = "tiQ", # specify content (search box, etc)
deferRender = TRUE,
scrollY = 300,
scroller = TRUE,
order = list(list(0, 'asc')),
columnDefs = list(
list(
visible = FALSE,
targets = c(1,2,3,4,6,7)
)
),
buttons = list(
I("colvis") # turn columns on and off
)
),
colnames = c(
"Name" = "name",
"Beschreibung" = "description",
"Website" = "url",
"Longitude" = "longitude",
"Latitude" = "latitude",
"Typ" = "type",
"ID" = "ID",
"Marker Text" = "popup_content"
)
)
)The entire project is public on my github: https://github.com/thhaase/interactive_map.