---
title: Interactive Surface Visualization with surfwidget
author: Bradley Buchsbaum
date: '`r Sys.Date()`'
output:
  rmarkdown::html_vignette:
    toc: yes
    toc_depth: 2.0
    css: albers.css
    includes:
      in_header: albers-header.html
vignette: |
  %\VignetteIndexEntry{Interactive Surface Visualization with surfwidget}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
params:
  family: teal
  preset: homage
resource_files:
- albers.css
- albers.js
- albers-header.html

---

This vignette focuses on interactive 3D visualization using `surfwidget()`.
For RGL-based 3D plots, see `vignette("displaying-surfaces")`. For
multi-view, publication-quality figures with colourbars and atlas
outlines, see `vignette("surface-figures")`.

```{r setup, include = FALSE}
# Ensure rgl uses a NULL device when knitting (prevents OpenGL segfaults on headless)
Sys.setenv(RGL_USE_NULL = "TRUE")
options(rgl.useNULL = TRUE)

if (requireNamespace("ggplot2", quietly = TRUE) && requireNamespace("albersdown", quietly = TRUE)) ggplot2::theme_set(albersdown::theme_albers(family = params$family, preset = params$preset))
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  warning = FALSE,
  message = FALSE,
  out.width = "100%",
  fig.height = 6
)

# Ensure htmlwidgets dependencies are properly loaded
library(htmlwidgets)
library(neurosurf)

# Load example data
white_lh_asc <- system.file("extdata", "std.8_lh.smoothwm.asc", package="neurosurf")
white_lh <- read_surf(white_lh_asc)
white_lh_smooth <- smooth(white_lh, type="HCLaplace", delta=.2, iteration=5)

# Prepare sample data
set.seed(123)
random_vals <- rnorm(length(nodes(white_lh_smooth)))

# Curvature underlay: provides subtle anatomical texture (gyri/sulci shading)
curv_vals <- curvature(white_lh_smooth)
curv_range <- as.numeric(stats::quantile(
  curv_vals,
  probs = c(0.02, 0.98),
  na.rm = TRUE,
  names = FALSE
))
curv_cmap <- grDevices::colorRampPalette(c("#707070", "#E0E0E0"))(256)
```

```{r albers-classes, echo=FALSE, results='asis'}
cat(sprintf(
  paste0(
    '<script>document.addEventListener("DOMContentLoaded",function(){',
    'document.body.classList.remove("palette-red","palette-lapis","palette-ochre","palette-teal","palette-green","palette-violet","preset-homage","preset-study","preset-structural","preset-adobe","preset-midnight");',
    'document.body.classList.add("palette-%s","preset-%s");',
    '});</script>'
  ),
  params$family,
  params$preset
))
```

## Introduction

The `surfwidget()` function provides interactive 3D visualization of brain surfaces using HTML widgets. This creates web-based viewers with real-time rotation, zooming, and interactive exploration capabilities.

## Quick Start

Create a small widget to confirm things are working, then jump to richer examples below.

```{r system-check}
surfwidget(
  white_lh_smooth,
  width  = "100%",
  height = "420px",
  curvature = curv_vals,
  config = list(
    ambientLightColor = "#404040",
    initialZoom = 2,
    showControls = FALSE   # keep the panel hidden for the quick preview
  )
)
```

## Basic Surface Display

The simplest usage is to pass a `SurfaceGeometry` object directly:

```{r basic-widget, results='asis'}
# Create basic interactive surface
basic_widget <- surfwidget(
  white_lh_smooth,
  width  = "100%",
  height = "400px",
  curvature = curv_vals,
  config = list(
    ambientLightColor = "#404040",
    initialZoom = 2
  )
)
basic_widget
```

## Data Visualization

Display data mapped onto surface vertices using a `NeuroSurface` object:

```{r data-widget, results='asis'}
# Create NeuroSurface with data
nsurf <- NeuroSurface(white_lh_smooth, indices=1:length(random_vals), data=random_vals)

# Create widget with data overlay
data_widget <- surfwidget(nsurf, 
                         cmap = heat.colors(256), 
                         irange = c(-2, 2),
                         width = "100%", 
                         height = "400px",
                         curvature = curv_vals,
                         config = list(
                           ambientLightColor = "#404040",
                           initialZoom = 2
                         ))

data_widget
```

## Advanced Configuration

Fine-tune the appearance with custom configuration:

```{r advanced-widget, results='asis'}
# Create ColorMappedNeuroSurface with threshold
color_mapped_surf <- ColorMappedNeuroSurface(
  white_lh_smooth, 
  indices = 1:length(random_vals), 
  data = random_vals,
  cmap = rainbow(256),
  irange = c(-2.5, 2.5),
  thresh = c(-1, 1)
)

# Advanced configuration
advanced_config <- list(
  shininess = 60,
  specularColor = "#ffffff",
  ambientLightColor = "#404040",
  directionalLightColor = "#ffffff",
  directionalLightIntensity = 0.7,
  flatShading = FALSE
)

# Add a subtle anatomical underlay using curvature so thresholded data doesn't
# "float" on a blank white surface.
underlay_layer <- list(
  label = "curvature",
  data = curv_vals,
  cmap = curv_cmap,
  color_range = curv_range,
  alpha = 1
)

# Keep the main data layer on top (inherits data/cmap/range/threshold from the
# ColorMappedNeuroSurface object).
data_layer <- list(label = "data")

advanced_widget <- surfwidget(color_mapped_surf, 
                             layers = list(underlay_layer, data_layer),
                             config = c(advanced_config, list(initialZoom = 2)), 
                             alpha = 0.9,
                             width = "100%", 
                             height = "450px")

advanced_widget
```

## Vertex-Colored Surfaces

Create surfaces with direct vertex coloring:

```{r vertex-widget, results='asis'}
# Create vertex colors based on coordinates
x_coords <- coords(white_lh_smooth)[, 1]
vertex_colors <- ifelse(x_coords > median(x_coords), "#FF6B6B", "#4ECDC4")

# Create VertexColoredNeuroSurface
vertex_surf <- VertexColoredNeuroSurface(
  geometry = white_lh_smooth, 
  indices = 1:length(vertex_colors), 
  colors = vertex_colors
)

# Custom material settings
material_config <- list(
  shininess = 20,
  specularColor = "#333333",
  ambientLightColor = "#404040"
)

vertex_widget <- surfwidget(vertex_surf, 
                           curvature = curv_vals,
                           config = c(material_config, list(initialZoom = 2)), 
                           alpha = 0.8,
                           width = "100%", 
                           height = "400px")

vertex_widget
```

## Interactive Controls

When the widgets display properly, they include several interactive controls:

- **Rotation**: Click and drag to rotate the surface
- **Zoom**: Mouse wheel or pinch gestures to zoom in/out
- **Pan**: Right-click and drag to pan the view
- **Control Panel**: Adjust lighting, materials, color mapping, and viewpoints
  - **Lighting**: Ambient and directional light colors and intensity
  - **Material**: Surface shininess (metalness/roughness)
  - **Camera**: Reset camera position and orientation
  - **Color Map**: Real-time adjustment of intensity and threshold ranges
  - **Viewpoint**: Switch between anatomical views (lateral, medial, ventral, posterior)
  - **SSAO**: Screen-space ambient occlusion for enhanced depth perception

## Troubleshooting

**Testing in Interactive R:**

All `surfwidget()` examples should work perfectly when run in an interactive R console:

```{r eval=FALSE}
# This should work in interactive R:
library(neurosurf)
white_lh_asc <- system.file("extdata", "std.8_lh.smoothwm.asc", package="neurosurf")
white_lh <- read_surf(white_lh_asc)
white_lh_smooth <- smooth(white_lh, type="HCLaplace", delta=.2, iteration=5)

# Basic widget
surfwidget(white_lh_smooth, width = "100%", height = "400px")

# With data
random_vals <- rnorm(length(nodes(white_lh_smooth)))
nsurf <- NeuroSurface(white_lh_smooth, indices=1:length(random_vals), data=random_vals)
surfwidget(nsurf, cmap = heat.colors(256), irange = c(-2, 2))
```

**Alternative: Save to File**

For guaranteed display, save widgets to standalone HTML files:

```{r eval=FALSE}
widget <- surfwidget(white_lh_smooth, width = "100%", height = "400px")
htmlwidgets::saveWidget(widget, "interactive_surface.html", selfcontained = TRUE)
# Open the resulting HTML file in your browser
```

## Advantages over Static Plots

Interactive widgets offer several advantages:

- **Real-time interaction**: Rotate, zoom, and pan without re-rendering
- **Dynamic controls**: Adjust visualization parameters interactively
- **Web-based**: Works in HTML documents, Shiny apps, and R Markdown
- **Touch support**: Works on tablets and mobile devices
- **High-quality rendering**: Uses WebGL for smooth, hardware-accelerated graphics
- **Data exploration**: Click on vertices to see coordinate and data values
- **Multiple viewpoints**: Easily switch between anatomical orientations

These interactive capabilities make `surfwidget()` ideal for exploratory data analysis and interactive presentations.

## Next Steps

- `vignette("displaying-surfaces")` — RGL-based 3D rendering with curvature shading, data overlays, and PNG snapshots.
- `vignette("surface-figures")` — publication-quality multi-view layouts with colourbars and atlas outlines.
- `vignette("introduction-to-neurosurf")` — the data structures (`SurfaceGeometry`, `NeuroSurface`, `NeuroSurfaceVector`) behind these visualizations.
