leafem icon indicating copy to clipboard operation
leafem copied to clipboard

addFgb uses wrong label and layerId

Open trafficonese opened this issue 1 year ago • 1 comments

Wrong Label

When a vector is used for label they are mixed up, as flatgeobuf apparently doesnt handle the Geojson in a sequential way, but still always in the same order (not sure which order yet). So the following is not working with the cntr index. https://github.com/r-spatial/leafem/blob/830d010f6087ba85bb71d7391d78db60dc8fef53/inst/htmlwidgets/lib/FlatGeoBuf/fgb.js#L122-L126

Different layerId behaviour

The layerId in leaflet works differently and also a vector can be passed to identify single elements. Using a vector with the current versions throws this error:

Warning: Error in validateScalarName: Invalid argument 'name' (must be a non-empty character string and contain no '/' or '')

Currently the FBG-File is loaded as attachment using the layerId as name. Could we switch this to group instead or use a combination of group, file, url? Those values should be of length = 1 or?

Then we could also return the layerId in the mouse-events here: https://github.com/r-spatial/leafem/blob/830d010f6087ba85bb71d7391d78db60dc8fef53/inst/htmlwidgets/lib/FlatGeoBuf/fgb.js#L15

using something like this id: e.layer.feature.properties[layerId].toString()

The behaviour would still be different to leaflet, as we would have to pass a string indicating the column to be used as layerId (e.g. layerId = "id"), but at least we could identify which element was clicked exactly.

And another problem I encountered with this method. If the layerId column is a numeric, the tooltip will not be displayed and ths error comes up. The function .toString() or + "" didnt help.

Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'. at e._updateContent (leaflet.js:5:89421) at e.update (leaflet.js:5:88713) at e.onAdd (leaflet.js:5:88115) at e.onAdd (leaflet.js:5:94883) at e._layerAdd (leaflet.js:5:64708) at e.whenReady (leaflet.js:5:44748) at e.addLayer (leaflet.js:5:65087) at e.openTooltip (leaflet.js:5:96860) at e.openTooltip (leaflet.js:5:98033) at e._openTooltip (leaflet.js:5:98858)

Here is an example Shiny App to play around:

Click me
library(leafem)
library(leaflet)
library(shiny)
library(terra)
library(sf)

## Transform Data to FGB ############ 
linesdf <- st_as_sf(leaflet::atlStorms2005)
linesdf$id <- paste0("id_",1:nrow(linesdf))
shp <- vect(linesdf)
shp_ext <- unname(as.vector(ext(shp)))
fgb_path <- tempfile(fileext = ".fgb")
writeVector(shp, fgb_path, filetype = "FlatGeobuf")

## UI ##################
ui <- fluidPage(leafletOutput("map", height = 500),
                splitLayout(cellWidths = c("49%","49%"),
                            div(
                              h3("FGB"),
                              verbatimTextOutput("print_fgb")
                            ),
                            div(
                              h3("Leaflet"),
                              verbatimTextOutput("print_leaflet")
                            )))

## SERVER ##################
server <- function(input, output){
  output$map <- renderLeaflet({
    leaflet("map") %>%
      fitBounds(shp_ext[1], shp_ext[3], shp_ext[2], shp_ext[4]) %>%
      addTiles() %>%
      addFgb(fgb_path, fill = FALSE, group = "Lines_FGB",
             layerId = "id",
             popup = TRUE,
             label = .subset2(linesdf, "id")
             # label = "id"
      ) %>% 
      # leafgl::addGlPolylines(data = linesdf,
      #                        layerId = .subset2(linesdf, "id"),
      #                        color = "#337ab7",
      #                        opacity = 0.9,
      #                        popup = NULL,
      #                        group = "Strassengraph_Glify",
      #                        preserveDrawingBuffer = TRUE,
      #                        sensitivity = 0.001,
      #                        sensitivityHover = 0.03) %>% 
      leaflet::addPolylines(data = linesdf,
                            layerId = .subset2(linesdf, "id"),
                            label = .subset2(linesdf, "id"),
                            color = "#337ab7",
                            opacity = 0.9,
                            popup = NULL,
                            group = "Lines") %>% 
      addLayersControl(
        position = "topright",
        overlayGroups = c("Lines_FGB", "Lines"
        ),
        options = layersControlOptions(collapsed = F, autoZIndex = TRUE)
      )
    
  })
  
  ## Ouputs ###############
  output$print_fgb <- renderPrint({
    click <- req(input$map_shape_click)
    req(click$group == "Lines_FGB")
    df <- linesdf[.subset2(linesdf, "id") == click[["id"]],]
    if (nrow(df) == 0) {
      showNotification("not found")
    } else {
      leafletProxy("map") %>% 
        clearGroup("sel") %>% 
        addPolylines(data = df, label = df$id, group="sel", color = "red",
                     options = pathOptions(interactive = FALSE))
    }
    print(click)
  })
  output$print_leaflet <- renderPrint({
    click <- req(input$map_shape_click)
    req(click$group == "Lines")
    df <- linesdf[.subset2(linesdf, "id") == click[["id"]],]
    if (nrow(df) == 0) {
      showNotification("not found")
    } else {
      leafletProxy("map") %>% 
        clearGroup("sel") %>% 
        addPolylines(data = df, label = df$id, group="sel", color = "red",
                     options = pathOptions(interactive = FALSE))
    }
    print(click)
  })
}

shinyApp(ui = ui, server = server)

trafficonese avatar May 28 '24 19:05 trafficonese

I just saw that this is expected, when writing the FGB. It should work with SPATIAL_INDEX=NO" as described here https://github.com/r-spatial/leafem/issues/53#issuecomment-1059087041

fl = tempfile(fileext = ".fgb")
sf::st_write(
  obj = franconia
  , dsn = fl
  , driver = "FlatGeobuf"
  , layer_options = c("SPATIAL_INDEX=NO")
)

trafficonese avatar Jun 02 '24 08:06 trafficonese