---
title: "State-first composition with dragmapr"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{State-first composition with dragmapr}
  %\VignetteEngine{knitr::rmarkdown}
  \usepackage[utf8]{inputenc}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5
)
have_dragmapr <- requireNamespace("dragmapr", quietly = TRUE)
```

`explodemap` computes the *geometry* of an exploded layout. Manual composition
-- nudging regions and labels until the map reads well -- belongs to the
[dragmapr](https://prigasg.github.io/dragmapr/) editor. The bridge between them
is a single, reusable **composition object**: a `dragmapr_state`.

The workflow is **compute once, then compose and render from the state**:

```
explode_grouped()  ->  as_dragmapr_state()  ->  dragmapr_edit()  ->  focus_map(state = )
   (geometry)            (handoff)                (compose)            render_dragged_map(state = )
```

## 1. Compute the layout

```{r compute}
library(explodemap)

# A few regions, each with several units.
unit_square <- function(x0, y0, size = 40000) {
  sf::st_polygon(list(rbind(
    c(x0, y0), c(x0 + size, y0), c(x0 + size, y0 + size),
    c(x0, y0 + size), c(x0, y0)
  )))
}

grid <- expand.grid(col = 0:2, row = 0:2)
regions <- sf::st_sf(
  region = rep(c("A", "B", "C"), each = 3),
  unit   = sprintf("u%02d", seq_len(9)),
  geometry = sf::st_sfc(
    lapply(seq_len(9), function(i) unit_square(grid$col[i] * 50000, grid$row[i] * 50000)),
    crs = 3857
  )
)

layout <- explode_grouped(regions, region_col = "region")
plot(layout)
```

## 2. Hand the layout over as a state

`as_dragmapr_state()` is the preferred handoff. It converts the exploded anchors
into metre deltas and records the projected CRS plus a `geometry_id`, so the
result is a durable, reproducible composition:

```{r handoff, eval = have_dragmapr}
state <- as_dragmapr_state(layout)
state
```

> The older `as_dragmapr()` returns a raw `dragmapr_layout` (geometry plus
> offset tables). It remains supported as a low-level escape hatch, but
> `as_dragmapr_state()` is the recommended entry point.

## 3. Compose

Open the dragmapr editor seeded with the state. In Shiny, capture each edit back
into a state with `dragmapr::dragmapr_widget_state()`:

```{r compose, eval = FALSE}
dragmapr::dragmapr_edit(layout, state = state)
```

## 4. Render the composed state

Every downstream renderer accepts the state via `state =`. The interactive focus
map can even reopen on a saved selection with `restore_selection = TRUE`:

```{r render-focus, eval = FALSE}
state$selected_feature <- "B"
focus_map(layout, state = state, group_col = "region", restore_selection = TRUE)
```

And the static renderer reproduces the composition from geometry plus state,
with no recomputation:

```{r render-static, eval = FALSE}
dragmapr::render_dragged_map(
  layout$sf_grouped,
  region_col = "region",
  state = state,
  file = "composed.png"
)
```

The state also flows through `update_exploded_layout()`, so an edited
composition can be folded back onto the grouped layout object itself.

For a complete runnable script, see
`system.file("examples/state_first_workflow.R", package = "explodemap")`.

For a fuller cross-package example that includes layout diagnostics,
label-aware parameter search, a simulated editorial pass, JSON state
persistence, `focus_map()`, and `dragmapr::render_dragged_map()`, run:

```{r full-cross-package, eval = FALSE}
source(system.file(
  "examples/explodemap_dragmapr_pipeline.R",
  package = "explodemap"
))
```
