% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/orbit-3d.R
\name{orbit_3d}
\alias{orbit_3d}
\title{Create an interactive drag-to-rotate ggcube}
\usage{
orbit_3d(
  plot,
  pitch = NULL,
  roll = NULL,
  yaw = NULL,
  n = 36,
  loop = NULL,
  start = NULL,
  max_frames = 500,
  width = 480,
  height = 480,
  res = 96,
  cores = 1,
  device = "png",
  progress = interactive(),
  file = NULL
)
}
\arguments{
\item{plot}{A ggplot object that uses \code{\link[=coord_3d]{coord_3d()}}.}

\item{pitch, roll, yaw}{Rotation angles in degrees. Each is either a single
value (held fixed) or a length-2 range \code{c(from, to)} that becomes a
draggable axis. For \code{yaw}, using a larger value for \code{from} than \code{to} gives
more natural results. Values specified here replace the ones specified in
\code{coord_3d()}. See Details.}

\item{n}{Grid resolution. For a 1D orbit, a single number giving the
frame count. For a 2D orbit, a length-2 vector giving the counts for
the horizontal and vertical screen axes respectively (in that order, x then y).
Its length must match the number of ranged parameters. Default is 36.}

\item{loop}{Controls seamless wraparound. \code{NULL} (default)
auto-detects looping independently for each axis by checking whether that
axis returns to its starting view. \code{TRUE} or \code{FALSE} force
wrapping on or off for all axes.}

\item{start}{Initial viewing angle(s) the orbit opens at, given in
degrees as a named vector matching the variable axes, e.g.
\code{start = c(yaw = 30)} or \code{start = c(yaw = 30, roll = 45)}. For a
1D orbit a bare scalar (e.g. \code{start = 30}) is also accepted. The
orbit opens at the frame nearest each given angle. Any variable axis not
named in \code{start} opens at the midpoint of its range, as does every
axis when \code{start = NULL} (the default). Naming an axis that is
fixed rather than variable throas an error.}

\item{max_frames}{Safety cap on the total number of rendered frames
(\code{prod(n)}). A 2D grid can become very large; if the requested grid
exceeds this cap the function errors rather than rendering. Raise it to
allow larger grids. Default is 500.}

\item{width, height}{Dimensions of the animation in pixels. Defaults to
480 x 480.}

\item{res}{Resolution in ppi for the rendered frames. Default is 96.
Controls the size of point-based text/lines/point elements relative to
the plot. See \code{?grDevices::png} for details.}

\item{cores}{Number of CPU cores for parallel frame rendering. Default
is 1 (sequential). Values greater than 1 use \code{\link[parallel:parLapply]{parallel::parLapply()}}
to render frames in parallel, which can significantly speed up
animation of complex plots. Note that progress reporting is not
available during parallel rendering.}

\item{device}{The graphics device to use for rendering frames.
Default is \code{"png"}. Other options include \code{"ragg_png"}
(requires the \pkg{ragg} package).}

\item{progress}{Whether to print a progress bar. Ignored when \code{cores > 1}.}

\item{file}{Optional path to write a self-contained HTML file (via
\code{\link[htmlwidgets:saveWidget]{htmlwidgets::saveWidget()}}). If \code{NULL} (default), no file is written and
the widget is simply returned for display or embedding.}
}
\value{
A \code{orbit_3d} htmlwidget. Printed at the console it opens in the
RStudio Viewer or browser; in a knitr document it embeds automatically;
in Shiny use \code{\link[=orbit3dOutput]{orbit3dOutput()}} and \code{\link[=renderOrbit3d]{renderOrbit3d()}}.
}
\description{
Creates an interactive HTML widget that you can rotate by dragging.
Pre-renders a set of ggcube plots across a 1D or 2D grid of rotation angles
and packages them as an \pkg{htmlwidgets} widget. The widget displays in the
RStudio Viewer, embeds in R Markdown and Quarto documents, works in Shiny
(see \code{\link[=orbit3dOutput]{orbit3dOutput()}}), and can be written to a self-contained HTML
file with \verb{file =}. When viewing it, navigate through the views by dragging
the image or using the keyboard arrows.
}
\section{Specifying rotation}{

Each of \code{pitch}, \code{roll}, and \code{yaw} is given either as a
single value (held fixed) or as a length-2 range \code{c(from, to)} that
is a variable, draggable axis. The number of ranges determines the
interaction:
\itemize{
\item One range gives a 1D orbit: horizontal drag (or left/right
keyboard arrows) vary that one parameter across its range.
\item Two ranges give a 2D orbit: horizontal drag (or left/right
keyboard arrows) vary one parameter while vertical drag/arrows vary
the other.
}
At least one range is required. Supplying three ranges is an error.

For a 2D orbit, the horizontal (x) and vertical (y) axes are assigned
from whichever parameters are ranged, by priority. The x axis takes the
highest-priority ranged parameter in the order \code{yaw}, \code{pitch},
\code{roll}; the y axis takes the highest-priority remaining ranged
parameter in the order \code{roll}, \code{pitch}. In the common case
\code{yaw = c(0, 360), roll = c(...)} this puts yaw on horizontal drag and
roll on vertical drag.

The range direction follows the order the values are written: for example
\code{yaw = c(360, 0)} rotates the opposite way from \code{yaw = c(0, 360)}.
}

\section{Looping}{

When a variable axis returns to its starting view (for example a full
\code{yaw = c(0, 360)} turn), that axis loops seamlessly: dragging past
either end wraps around. This is detected per axis by comparing the first
and last angle modulo 360, so a full-turn axis wraps while a partial range
(such as \code{roll = c(-90, 90)}) clamps. \code{loop} can force this on or
off for all axes at once.
}

\section{Keyboard}{

Once the widget has focus, the arrow keys step one frame: left/right move
the horizontal axis, and (in a 2D orbit) up/down move the vertical axis.
}

\examples{
\dontshow{if (requireNamespace("base64enc", quietly = TRUE) && requireNamespace("htmlwidgets", quietly = TRUE)) withAutoprint(\{ # examplesIf}
\donttest{
p <- ggplot(mountain, aes(x, y, z, fill = z, color = z)) +
  geom_surface_3d(linewidth = .25) +
  coord_3d(light = light(anchor = "camera",direction = c(1, 1, 0)),
           ratio = c(1.5, 2, 1)) +
  scale_fill_viridis_c() + scale_color_viridis_c() +
  theme_void()

# 1D drag-to-rotate turntable (small n to minimize runtime)
orbit_3d(p, yaw = c(360, 0), n = 12)

# 2D orbit: drag horizontally to spin (yaw), vertically to tilt (roll)
# (note you could increase `cores` to speed up compute time)
orbit_3d(p, yaw = c(360, 0), roll = c(-90, 0), n = c(20, 10),
            width = 1000, height = 1000, cores = 1)

# Save to a chosen path
orbit_3d(p, yaw = c(360, 0), n = 12,
            file = file.path(tempdir(), "surface.html"))
}
\dontshow{\}) # examplesIf}
}
\seealso{
\code{\link[=animate_3d]{animate_3d()}} for GIF/MP4 output.
\link{orbit_3d-shiny} for including orbits in  Shiny apps.
}
