---
title: "Use geoarrowWidget with an existing widget"
format: html
vignette: >
  %\VignetteIndexEntry{Use geoarrowWidget with an existing widget}
  %\VignetteEngine{quarto::html}
  %\VignetteEncoding{UTF-8}
---

A general usage pattern of `geoarrowWidget` is to enable attaching data to an
existing widget and then using some JavaScript to update/extend the functionality 
of the existing widget.

## Using {listviewer} to examine a (geo)arrow file

As an example, we will use `listviewer::jsonedit()` to examine a (geo)arrow file.

First, we create some spatial data from scratch:

```{r, message=FALSE}
library(geoarrowWidget)
library(nanoarrow)
library(geoarrow)
library(listviewer)
library(wk)
library(htmlwidgets)

### generate some random wk points data ========================================
n = 1e2
dat = data.frame(
  id = 1:n
  , fillColor = hcl.colors(n)
  , radius = sample.int(15, n, replace = TRUE)
  , geom = xy(
    x = runif(n, -160, 160)
    , y = runif(n, -40, 40)
    , crs = wk_crs_projjson("EPSG:4326")
  )
)
```

Then, we convert to and save the data as a (geo)arrow file:

Note, we need to explicitly infer the geoarrow schema, so that the geometry
is properly handled, especially the geometry encoding and the crs.

```{r}
fl = tempfile()
dir.create(fl)
path = file.path(
  fl
  , "test.arrow"
)

interleaved = TRUE

data_stream = as_nanoarrow_array_stream(
  dat
  , geometry_schema = infer_geoarrow_schema(
    dat
    , coord_type = ifelse(interleaved, "INTERLEAVED", "SEPARATE")
  )
  , schema = infer_nanoarrow_schema(dat)
)

data_stream$get_schema()

write_nanoarrow(data_stream, path)
```

Next, we create an empty listviewer widget and attach the relevant JavaScript 
libraries and the geoarrow file. We explicitly name the widget via the `elementId`
so that we can find the widget in the document and subsequently modify it.

```{r}
wgt = jsonedit(listdata = list(""), elementId = "lv-example")
wgt = attachGeoarrowDependencies(widget = wgt)
wgt = attachData(widget = wgt, file = path, name = "mydata")
```

Finally, we specify the JavaScript code that handles the population of the created
JsonEditor in the browser with our geoarrow data and render the widget.

```{r}
js_code = htmlwidgets::JS(
  'function (el, x, data) {

        // find data attachment in document
        
        let attachment = document.getElementById(data.name + "-geoarrowWidget-attachment");
        
        // find listviewer jsonedit element in document and delete current contents
        
        let jse = document.getElementById("lv-example");
        jse.innerHTML = null;

        // load data from attachment into jsonedit element identified and emptied earlier
        // metadata parsing from here:
        // https://www.geeksforgeeks.org/javascript/how-to-convert-map-to-json-in-javascript/
        
        fetch(attachment.href)
          .then(result => Arrow.tableFromIPC(result))
          .then(arrow_table => {
          
            let newed = new JSONEditor.JSONEditor({
              target: jse, 
              props: {
                content: {
                  json: [{
                    "geoarrow table": JSON.parse(JSON.stringify(arrow_table)),
                    "geoarrow metadata": JSON.parse(JSON.stringify(Object.fromEntries(arrow_table.schema.fields[3].metadata)))
                  }]
                }
              }
            });
            //debugger;
            console.log(arrow_table);

          });
  }'
)

onRender(wgt, js_code, data = list(name = "mydata"))
```

This now nearly looks like the data is defined in JavaScript, but not quite... If 
you open the browser console and inspect and compare the console log of the 
`arrow_table`, you'll see that e.g. it carries the CRS metatdata which is lost
in the `geoarrow table` in the JSONEditor. This is why we parse it separately as 
`geoarrow metadata`.

In this (somewhat convoluted) structure, the actual data values can be found at e.g. for the `radius` column:

`[]` > `0` > `geoarrow table` > `batches` > `0` > `data` > `children` > `2` > `values` 

The geometry column (child 3) has 2 children itself, so that access to the longitude coordinates is:

`[]` > `0` > `geoarrow table` > `batches` > `0` > `data` > `children` > `3` > `children` > `0` > `values`

Note, that the hex representation of the `fillColor` column (child 1) is internally converted to some numerical representation, which is why it has 700 values instead of just 100.
