import type {
CandleGap,
CandleGapsConfig,
ChartGap,
ChartGapsConfig,
LiveChartHandle,
LiveChartPoint,
ReferenceLine,
SeriesConfig,
} from "react-native-livechart";
import type { SharedValue } from "react-native-reanimated";
.d.ts and JSDoc remain the canonical reference (your editor surfaces them on hover);
the most-used shapes are reproduced here.
Data
type CanvasMode = "transparent" | "opaque";
CanvasMode controls whether the Skia canvas participates in transparent composition or owns its
background. On Android, opaque mode selects SurfaceView. See
Android surface rendering.
interface LiveChartPoint {
time: number; // unix seconds
value: number;
}
interface CandlePoint {
time: number; // bucket start, unix seconds
open: number;
high: number;
low: number;
close: number;
volume?: number; // optional traded volume; drives the volume bars (candle mode)
}
type CandleGapKind = "no-trades" | "unavailable" | "unknown";
interface CandleGap {
from: number; // inclusive, unix seconds
to: number; // exclusive, unix seconds
kind: CandleGapKind;
label?: string;
}
// Renderer-neutral aliases used by lineGaps. The candle names remain available.
type ChartGapKind = CandleGapKind;
type ChartGap = CandleGap;
interface SeriesConfig {
id: string;
data: LiveChartPoint[];
value: number; // latest live value
color?: string;
label?: string;
visible?: boolean; // default true
style?: "solid" | "dashed";
intervals?: [number, number];
curve?: "monotone" | "linear"; // interpolation; default "monotone"
simplify?: number; // per-series path tolerance in px; inherits line.simplify
strokeWidth?: number;
glow?: boolean;
kind?: "outcome" | "derived";
valueLabel?: string;
}
interface LiveChartCoreProps {
// UI-thread value from 0 (hidden) to 1 (fully visible); default 1.
seriesOpacity?: SharedValue<number>;
}
seriesOpacity dims plot data (line and area fill, candles, value lines, badges,
and inline values) without dimming axes, legends, reference lines, or scrub UI.
While it is below 1, live dots and pulse rings fade completely out so a dimmed
stroke cannot show through them; they return once the multiplier reaches 1.
See Line & area or
Multi-series.
Momentum
type Momentum = "up" | "down" | "flat";
interface MomentumConfig {
threshold?: number; // default 0.12
lookback?: number; // default 20
}
Annotations
type MarkerKind = "trade" | "boost" | "graduation" | "winner" | "clawback";
interface Marker {
id: string;
time: number; // unix seconds
kind: MarkerKind;
seriesId?: string; // anchor to a series line (multi-series)
value?: number; // absolute y (takes precedence over seriesId)
color?: string;
icon?: string; // text/emoji glyph override
image?: SkImage; // image glyph override
pill?: boolean; // draw the icon in a filled circular badge
size?: number; // default 16
side?: "above" | "below" | "center"; // sit off the anchor (default "center")
data?: unknown; // surfaced on onMarkerPress
}
// Fires on tap (there is no hover on touch); `null` on a miss.
interface MarkerPressEvent {
marker: Marker;
point: { x: number; y: number };
index: number; // index in the markers array
isGrouped: boolean; // true when a collapsed cluster (count badge) was tapped
members?: Marker[]; // the cluster's markers when isGrouped
}
// Second argument to renderMarker — cluster / position state.
interface MarkerRenderContext {
index: number;
isGrouped: boolean;
groupCount: number;
side: "above" | "below" | "center";
}
// Object form of the `markerCluster` prop (tunes stacked collision). Passing it
// implies mode: "stacked" unless you set mode explicitly.
interface MarkerClusterConfig {
mode?: "anchored" | "stacked";
direction?: "horizontal" | "vertical"; // fan sideways (default) or pile into a column
overlap?: number; // 0 (touching) – 1 (stacked); default 0.75
maxBeforeGroup?: number; // collapse a run past this many; default 5
maxVisible?: number; // vertical columns only: keep this many oldest glyphs; default unbounded
groupBadge?: "count" | "marker" | MarkerGroupBadge; // collapsed look: count circle
// (default), the representative marker's own glyph, or a
// dedicated custom badge you supply (object form)
showGroupCount?: boolean; // with a non-count badge, stamp the count in the corner; default false
}
// Badge options for a collapsed cluster. Use letterSpacing by itself to tune the
// built-in count, or add image/icon for a dedicated glyph. @experimental
interface MarkerGroupBadge {
letterSpacing?: number; // extra px between count digits; default 0
image?: SkImage; // custom Skia image (precedence over icon)
icon?: string; // text/emoji glyph (when image unset)
color?: string; // icon / pill color; defaults to a palette accent
pill?: boolean; // wrap the icon in a filled circular badge
size?: number; // glyph box size in px; default 16
}
interface TradeEvent {
side: "buy" | "sell";
price: number;
size: number;
time: number; // unix seconds
symbol?: string;
}
interface ReferenceLine {
id?: string; // stable identity; supply when lines may reorder
// Form A — horizontal line:
value?: number;
// Form B — time-varying line (sorted unix-second points):
series?: LiveChartPoint[];
extendToNow?: boolean; // flat-extend the last value to live; default true
// Form C — horizontal band:
valueFrom?: number;
valueTo?: number;
// Form D — vertical time band (unix seconds):
from?: number;
to?: number;
// Shared:
label?: string;
strokeWidth?: number;
intervals?: [number, number];
color?: string;
fillColor?: string; // band fill; defaults to color, then palette refLine
fillOpacity?: number; // default 0.16
strokeOpacity?: number; // line / series / band-border opacity; default 1
fullWidth?: boolean; // span edge-to-edge through the Y-axis gutter (Form A/C);
// label/badge stay in the plot. default false
labelColor?: string;
labelPosition?: "left" | "center" | "right";
showValue?: boolean;
excludeFromRange?: boolean;
// Pill badge for a Form-A line (working orders, alerts, targets) — pinned to an
// edge with a dashed connector; auto-pins with a chevron when off-screen:
badge?: boolean | ReferenceLineBadgeConfig;
badgeBackground?: string; // fallback for badge.background; default theme tooltipBg
badgeBorderColor?: string; // fallback for badge.borderColor; default the line color
badgeRadius?: number; // fallback for badge.radius; default 5
// Legacy off-axis badge (prefer `badge`, which also shows in-range + supports an icon):
offAxisBadge?: boolean;
offAxisBadgeLabel?: string;
// Draggable (Form A only) — grab the line and drag it along the Y-axis:
draggable?: boolean; // default false
snap?: number; // round the dragged value to this increment
bounds?: [number, number]; // hard-clamp the draggable value
onChange?: (value: number) => void; // during drag (de-duped to value changes)
onCommit?: (value: number) => void; // on release — pair with a controlled `value`
onDragIn?: (value: number) => void; // value entered the visible range / bounds
onDragOut?: (value: number) => void; // value left the visible range / hit a bound
}
interface ReferenceLineBadgeConfig {
position?: "left" | "center" | "right"; // edge to pin to ("center" floats at the
// value, no connector); default "left"
icon?: string; // leading glyph (chart font), like Marker.icon
text?: boolean; // show the label/value; default true. false → icon-only
background?: string; // falls back to badgeBackground, then theme tooltipBg
borderColor?: string; // falls back to badgeBorderColor, then the line color
borderWidth?: number; // border stroke width; default 1
radius?: number; // corner radius; falls back to badgeRadius, then 5
textColor?: string; // label/icon color; falls back to labelColor, then theme
fontSize?: number; // badge font size; falls back to the chart font
fontFamily?: string; // badge font family; falls back to the chart font
fontWeight?: FontWeight; // badge font weight; falls back to the chart font
offsetX?: number; // nudge the whole badge from its anchor; default 0
offsetY?: number; // nudge the whole badge from its anchor; default 0
}
interface ReferenceLineRenderProps {
line: ReferenceLine; // the line being rendered
index: number; // its index in `referenceLines`
value: SharedValue<number>; // live Y-axis value (tracks dragging)
valueStr: SharedValue<string>; // value formatted with the chart's formatValue
y: SharedValue<number>; // canvas Y px of the line (-1 when not laid out)
inRange: SharedValue<boolean>; // whether the value is within the visible range
edge: SharedValue<"above" | "in" | "below">; // for a directional off-axis chevron
dragging: SharedValue<boolean>; // whether this line is currently being dragged
}
// `renderReferenceLine` replaces a tag in every state. `renderOffAxisReferenceLine`
// keeps the built-in in-range tag and shows the custom element only for edge !== "in".
interface ReferenceLineGroupingConfig {
radius?: number; // collapse lines whose value-Y are within this many px; default 18
badge?: ReferenceLineBadgeConfig; // count-pill styling (same style/shape config as a
// per-line badge: position, icon, colors, radius,
// border, textColor, font, offset)
format?: (count: number) => string; // label the count, e.g. n => `×${n}`; default String(n)
}
interface ChartSegment {
from?: number; // unix seconds; omit → chart's left edge
to?: number; // unix seconds; omit → live edge (now)
// Scrub-focus line styling (the headline interaction):
recolorLine?: boolean; // join scrub-focus dimming; default true. false → line
// never dims (divider/label still draw); behaves as a gap
mutedColor?: string; // de-emphasis color when NOT focused; default: palette.gridLabel
// (an alpha color, e.g. "rgba(154,160,166,0.4)", fades the line)
mutedColors?: string[]; // ≥2 → de-emphasis gradient; precedence over mutedColor
active?: boolean; // force-focus this segment without scrubbing; default false
// Divider + label (colors inherit the chart palette — no base color needed):
divider?: boolean; // dashed vertical line at `from`; default false
dividerColor?: string; // default: palette.refLine
label?: string; // caption — shown only with the divider; drawn in palette.refLabel
labelPosition?: "left" | "right"; // default "left"
}
Scrub payloads
interface ScrubPointCore {
time: number;
value: number;
x: number; // canvas X
y: number; // canvas Y
}
interface ScrubPoint extends ScrubPointCore {
candle?: CandlePoint; // candle mode only
gap?: ChartGap; // line or candle mode, when a bridged declared gap supplies value
}
interface ScrubPointMulti extends ScrubPointCore {
seriesValues: { id: string; label?: string; value: number }[];
}
// Payload for onScrubAction (order-ticket mode). `price` is the value at the
// reticle Y — a chosen level — not the line value at that time.
interface ScrubActionPoint {
price: number; // reticle-Y value, optionally snap-rounded
time: number; // unix seconds at the reticle X
x: number; // canvas X
y: number; // canvas Y
candle?: CandlePoint; // candle mode only — OHLC under the reticle X (context)
}
Config objects
These are the option shapes accepted by the matching props.interface CandleGapBridgeStyle {
color?: string;
opacity?: number;
strokeWidth?: number;
strokeCap?: "butt" | "round" | "square";
}
interface CandleGapBandStyle {
fillColor?: string;
fillOpacity?: number;
borderColor?: string;
borderOpacity?: number;
borderWidth?: number;
intervals?: [number, number];
}
interface CandleGapLabelStyle {
color?: string;
position?: "left" | "right";
}
interface CandleGapStyle {
bridge?: false | CandleGapBridgeStyle;
band?: false | CandleGapBandStyle;
label?: false | CandleGapLabelStyle;
}
interface CandleGapsConfig {
gaps: CandleGap[];
styles?: Partial<Record<CandleGapKind, CandleGapStyle>>;
}
type ChartGapBridgeStyle = CandleGapBridgeStyle;
type ChartGapBandStyle = CandleGapBandStyle;
type ChartGapLabelStyle = CandleGapLabelStyle;
type ChartGapStyle = CandleGapStyle;
type ChartGapsConfig = CandleGapsConfig;
interface LineConfig {
width?: number; // stroke width in px; default 2
color?: string; // line color override; defaults to palette accent
colors?: string[];// per-point gradient stops (left → right); wins over color
curve?: "monotone" | "linear"; // point interpolation; default "monotone"
// (smooth cubic). "linear" = straight segments / hard-edged.
simplify?: number; // screen-space path tolerance in px; default 0 (off).
// Removes only intermediate drawn points within the tolerance;
// source data, axis fitting, markers, and scrubbing stay exact.
join?: "round" | "miter" | "bevel"; // corner join; default "round".
// "miter" = sharp/angular peaks, "bevel" = flattened.
cap?: "round" | "butt" | "square"; // start/end cap; default "round".
// pair "butt" + join "miter" for a fully hard-edged line.
}
interface GradientConfig {
topOpacity?: number; // accent-derived top fill opacity
bottomOpacity?: number; // accent-derived bottom fill opacity
colors?: string[]; // explicit gradient stops (top → bottom), ≥ 2 entries;
// overrides topOpacity/bottomOpacity when provided
positions?: number[]; // optional stop positions (0..1, ascending), same
// length as colors; ignored if the lengths differ
}
interface AreaDotsConfig { // dot-lattice fill of the area beneath the line
spacing?: number; // lattice pitch (px) between dots, both axes; default 12
size?: number; // dot diameter (px); default 1.6
color?: string; // dot color; omit to derive a faint tint from the line color
opacity?: number; // overall field opacity (0..1); default 1
}
interface ThresholdConfig {
// The split value (Y-axis units). A SharedValue<number> for a single live
// benchmark, OR a LiveChartPoint[] for a time-varying threshold the split,
// band + marker follow point-for-point (clamps to its first/last value outside
// its range → flat-extends to the live edge). See the Threshold split guide.
// Provide value OR series (series wins).
value?: SharedValue<number> | LiveChartPoint[];
// LIVE time-varying threshold: like the LiveChartPoint[] form but a
// SharedValue — .set()/.modify() tracks on the UI thread, no re-render
// (a VWAP updated every tick). Points sorted by time, like `data`.
series?: SharedValue<LiveChartPoint[]>;
aboveColor?: string; // stroke at/above value; default palette up-green
belowColor?: string; // stroke below value; default palette down-red
fill?: boolean | { opacity?: number }; // line↔threshold P/L band; default off, opacity 0.16
includeInRange?: boolean; // fold the threshold into the Y-range fit (like reference lines); default false
extendToNow?: boolean; // series: extend flat past the last point to "now"; default true
line?: boolean | ThresholdLineConfig; // marker line at value; default off
}
interface ThresholdLineConfig {
label?: string; // label text, e.g. "Break-even"
labelPosition?: "left" | "right"; // "left" = inside plot (clear of y-axis); default "left"
labelAnchor?: "first" | "last"; // series: visible left-edge or live/right-edge value; default "last"
color?: string; // line + label color; default palette refLine/refLabel
labelColor?: string; // label text color; falls back to color, then palette refLabel
intervals?: [number, number]; // dash pattern; default [4, 4]
strokeWidth?: number; // default 1
showValue?: boolean; // append the formatted value to the label; default false
}
interface ThresholdBadgeRenderProps {
line: ThresholdLineConfig; // resolved marker-line config
value: SharedValue<number>; // live threshold value
valueStr: SharedValue<string>; // formatted with the chart's formatValue
y: SharedValue<number>; // live canvas Y (NaN when geometry is unavailable)
visible: SharedValue<boolean>; // whether the badge is inside the plot
}
interface BadgeConfig {
variant?: "default" | "minimal";
tail?: boolean; // pointed tail toward the dot; false = pill sits flush
// at the gutter edge (no tail space reserved); default true
background?: string;
position?: "right" | "left";
// Shape / style — all Skia-native, drawn in the batched canvas pass (no perf cost):
radius?: number; // corner radius (px); default capsule (pillHeight/2), clamped to that max
borderColor?: string; // pill border color; default none
borderWidth?: number; // border stroke width (px), only drawn with borderColor; default 1
textColor?: string; // label text color override; default variant/theme rule
fontSize?: number; // badge font size (px); falls back to the chart `font`
fontFamily?: string; // badge font family; falls back to the chart `font`
fontWeight?: FontWeight; // badge font weight; falls back to the chart `font`
offsetX?: number; // nudge the whole badge horizontally (px); default 0
offsetY?: number; // nudge the whole badge vertically (px); default 0
followViewEdge?: boolean; // while time-scrolled, track the price at the visible
// window's right edge (badge value/color + value line + dot);
// default false
}
interface PulseConfig {
interval?: number; duration?: number; maxRadius?: number;
opacity?: number; strokeWidth?: number;
}
interface ValueLineConfig { strokeWidth?: number; intervals?: [number, number]; color?: string }
// Shared styling for a straight line (the connector, valueLine, …). Omit `intervals` for solid.
interface LineStyleConfig { color?: string; strokeWidth?: number; intervals?: [number, number] }
interface ScrubConfig {
tooltip?: boolean; // existing master tooltip switch; false also suppresses seriesTooltip
// LiveChartSeries only: opt-in Morfi-style time + per-series value pills.
// false/omitted preserves the existing guide-only default.
seriesTooltip?: boolean | PerSeriesTooltipConfig;
dimTarget?: "future" | "otherCandles"; // default "future"; otherCandles hides the scrub line/dot in candle mode, falls back to future in line mode
dimOpacity?: number; // opacity of the selected dim target; clamped to [0, 1]; default 0.3
dimFadeMs?: number; // otherCandles fade-in/out duration; default 60; 0 = instant
crosshairLineColor?: string; crosshairDimColor?: string; // crosshairDimColor = legacy colored mask
crosshairStrokeWidth?: number; // line width in px; default 1
crosshairOvershoot?: number; // extend past top/bottom in px; preserves a custom top-tooltip stop; negatives clamp to 0; default 0
crosshairFade?: boolean; // fade near the live edge; default true
crosshairFadeDistance?: number; // visible line/dot/tooltip fade distance in px; negatives clamp to 0; default 4
crosshairLineCap?: "butt" | "round" | "square"; // omit to preserve the existing Skia default
crosshairDash?: number[] | boolean; // dash the crosshair line; true = [4,4], or explicit [on, off, …] px
tooltipBackground?: string; tooltipColor?: string; tooltipBorderColor?: string;
tooltipBorderRadius?: number; // pill corner radius; default 5
tooltipPlacement?: "side" | "top" | "bottom" | "point"; // default "side" (offset/flip); top/bottom center over the line; point floats above the scrub dot
tooltipMargin?: number; // gap (px) to the pinned plot edge (top for side/top, bottom for bottom); default 8
tooltipShowValue?: boolean; tooltipShowTime?: boolean; // default both true; drop a row (e.g. date-only)
panGestureDelay?: number; // press-and-hold ms before scrubbing activates; default 0
clampToPlot?: boolean; // plain scrub: ignore starts beyond the plot's X bounds and clamp active drags; default false
hideOverlaysOnScrub?: boolean; // fade markers + reference lines out while scrubbing; default false
snapToCandles?: boolean; // candle mode: snap the crosshair to candle centers (tick-to-tick); gaps between candles + line mode keep the raw X; default false
}
interface PerSeriesTooltipConfig {
alwaysShow?: boolean; // pin value pills to visible endpoints while idle; default false
bucketSeconds?: number; // omit to infer from the first visible series
formatSeriesValue?: (value: number, seriesId: string) => string; // UI-thread worklet
formatTimeRange?: (from: number, to: number) => string; // UI-thread worklet
maxLabelChars?: number; // ellipsis truncation; default 14
guideColor?: string;
guideWidth?: number; // default 1
guideDashPattern?: boolean | number[]; // default [3,3]; false = solid
timePillBackground?: string; timePillColor?: string; timePillBorderColor?: string;
timePillRadius?: number; timePillPaddingX?: number; timePillPaddingY?: number;
seriesPillBackground?: string;
seriesPillLabelColor?: string;
seriesPillValueColor?: string;
seriesPillBorderColor?: string;
seriesPillRadius?: number;
seriesPillPaddingX?: number; seriesPillPaddingY?: number;
seriesPillDotSize?: number; seriesPillDotGap?: number;
seriesPillLabelValueGap?: number;
intersectionDotSize?: number;
}
// Order-ticket mode (scrubAction). Opt-in — default off.
interface ScrubActionConfig {
icon?: string; // action-badge glyph; default "+"
background?: string; // action-badge background; default the accent / badge color
iconColor?: string; // icon + price-text color; default the badge text color
lineColor?: string; // horizontal level-line color; default palette.crosshairLine
text?: boolean; // show the price readout; default true. false → icon-only pill
timeBadge?: boolean; // date/time pill where the line meets the x-axis; default false
snap?: number; // round the reported price to this increment (e.g. 0.01, 0.5)
dismissOnTapOutside?: boolean; // empty-plot tap dismisses vs. re-places; default false
dismissOnAction?: boolean; // dismiss the reticle once the badge fires onScrubAction; default false
}
interface SelectionDotRingConfig {
color?: string; // ring color, defaults to the dot color
width?: number; // ring thickness past the dot, default 2
}
// The scrub-intersection dot (selectionDot). Default ON for LiveChart,
// OFF for LiveChartSeries (the crosshair + opt-in per-series tooltip dots mark it).
interface SelectionDotConfig {
size?: number; // dot radius, default 4
color?: string; // dot color, defaults to the line / leading-series color
ring?: boolean | SelectionDotRingConfig; // outer halo, default on
component?: ComponentType<SelectionDotProps>; // custom Skia dot; ignores size/color/ring
}
interface GridStyleConfig { color?: string; strokeWidth?: number; intervals?: number[]; opacity?: number }
interface YAxisConfig {
minGap?: number; // min px gap between grid lines; default 36
// Multiplier used to choose dynamic nice intervals without changing plotted
// values. Pair with formatValue using the same multiplier. Must be positive
// and finite; invalid values use 1. Unrepresentable scaled ranges fall back
// to source-unit intervals. Ignored with count. Default 1.
intervalScale?: number;
// Show a fixed number of evenly-spaced prices (top = high, bottom = low)
// instead of the dynamic nice-interval grid. Values track the live range each
// frame. `minGap` still floors the spacing; clamped to at most 15. Default 0.
count?: number;
// Place labels in a shared left-aligned column whose right edge sits this
// many px from the canvas edge. Omit for the centered-gutter placement.
labelRightMargin?: number;
// Gap between the shared label column and each grid/plain-reference-line end.
// Only applies with labelRightMargin. Default 0.
gridEndGap?: number;
// Float the price axis over a full-width plot instead of reserving a right
// gutter — the line/candles run to the edge and the labels float on top.
// Pairs with `timeScroll` (see the Time-scroll guide). Default false. @experimental
float?: boolean;
}
interface XAxisConfig { minGap?: number } // default 60
// Fades both axes while LiveChart is idle. @experimental
interface AxisAutoHideConfig {
fadeInMs?: number; // interaction-start fade duration; default 60
fadeOutMs?: number; // fade back to idle; default 250
idleOpacity?: number; // axes' resting opacity (0 = hidden); default 0
hideAfterMs?: number; // idle delay before fade-out; default 3000
}
// Volume bars below the candles (candle mode only). Bars normalize to the largest
// visible volume; the candle plot shrinks by `maxHeight` to make room. @see CandlePoint.volume
interface VolumeConfig {
upColor?: string; // bars for up (close ≥ open) candles; default palette.candleUp
downColor?: string; // bars for down candles; default palette.candleDown
maxHeight?: number; // reserved band height (px) = the tallest bar; default 48
radius?: number; // bar-top corner radius (px); default 2
opacity?: number; // opacity of the whole band (0..1); default 0.6
}
// Horizontal time-scrolling (pan back through history). @experimental
interface TimeScrollConfig {
gesture?: "holdToScrub" | "axisDrag"; // activation; default "holdToScrub"
scrubHoldMs?: number; // holdToScrub: press-hold (ms) before scrub engages; default 500
hideLiveOnScrollBack?: boolean; // hide live badge + dot + value line while scrolled back (they mark the off-screen live price); default true. Ignored with badge.followViewEdge
overscroll?: number; // fraction of the window (0–1) pan/zoom may travel past the data bounds into blank space (TradingView-style); default 0 (hard stops at the oldest data / live edge)
fling?: boolean; // keep release momentum after a fast drag; false stops exactly where the finger lifts. Default true.
}
// Tunes the return-to-live glide (the `returnToLive` prop). @experimental
interface ReturnToLiveConfig {
duration?: number; // glide duration (ms) back to live; default 450 (0 = instant snap)
}
// Tune/disable the built-in transition animations — the object form of `transitions`.
interface TransitionConfig {
reveal?: number; // grow-in when data appears, on timeframe change, or candle→line; default 600 (0 = snap)
mode?: number; // candle↔line crossfade (single-series LiveChart only); default 300 (0 = snap)
candleLerpSpeed?: number; // candle-width ease speed (0–1, like smoothing); candle mode; default 0.08 (1 = instant resize)
}
// Styling for the breathing loading shell — the object form of `loading`.
interface LoadingConfig {
color?: string; // squiggle + skeleton color; default theme gridLine
strokeWidth?: number; // squiggle stroke width; default the chart line strokeWidth
amplitude?: number; // base breathing-wave height (px); default 14
speed?: number; // breathing-wave speed multiplier; default 1 (0 freezes)
axisLabels?: boolean; // draw the skeleton Y-axis placeholders; default true (false = squiggle only)
}
// Pinch-to-zoom the visible time window (two-finger, focal-anchored). @experimental
interface ZoomConfig {
minTimeWindow?: number; // tightest window in seconds (max zoom-in); default timeWindow / 8
maxTimeWindow?: number; // widest window in seconds (max zoom-out); default the full data span
}
// Visible window reported by onVisibleRangeChange (unix seconds). @experimental
interface VisibleRange {
startSec: number; // left-edge time of the visible window
endSec: number; // right-edge time of the visible window
following: boolean; // true when at the live edge (not scrolled back / paused)
}
// Edge label (topLabel / bottomLabel). Default off — both opt-in.
interface AxisLabelConfig {
format?: (v: number) => string; // built-in value formatter; defaults to formatValue
color?: string; // text color; defaults to palette.gridLabel (muted)
// "left"/"right" pin to that edge (default "right"). "extrema" floats the label
// on the actual high (topLabel) / low (bottomLabel) data point. "extrema-edge"
// keeps the label on the top/bottom edge (x-aligned) with a dot + connector.
position?: "left" | "right" | "extrema" | "extrema-edge";
fontSize?: number; // built-in value text size (px); default 11
fontWeight?: FontWeight; // built-in value text weight; default platform default
fontFamily?: string; // built-in value text font family
dotColor?: string; // extrema modes — dot color; defaults to color
dotSize?: number; // extrema modes — dot diameter (px); default 7
dot?: boolean; // extrema modes — draw the marker dot; default true
// "extrema-edge" connector (dot → edge label). true = dashed default, false =
// none, or a LineStyleConfig. Default on (dashed) in "extrema-edge" mode.
connector?: boolean | LineStyleConfig;
render?: () => React.ReactElement | null; // custom element; overrides everything above
}
interface ChartInsets { top?: number; right?: number; bottom?: number; left?: number }
interface LeftEdgeFadeConfig { width?: number; startColor?: string; endColor?: string }
interface DotGlowConfig {
color?: string; // default: resolved dot fill color
radius?: number; // glow source-circle radius, default 7
blur?: number; // Skia blur radius, default 5
opacity?: number; // 0–1, default 0.18
}
interface DotRingConfig {
color?: string; // default: theme `badgeOuterBg`
width?: number; // default 2.5
}
// Shared live-dot styling (LiveChart `dot`; LiveChartSeries `dot` extends it)
interface DotConfig {
radius?: number; // color-filled dot radius, default 3.5
ring?: boolean | DotRingConfig; // crisp outer backing ring, default true
glow?: boolean | DotGlowConfig; // soft static glow, default false
show?: boolean; // @deprecated — prefer dot={false}; default true
color?: string; // dot fill, defaults to the line color
trackWhileParked?: boolean; // while scrolled back / overscrolled, the dot tracks the true live point — keeps pulsing, stays visible, hides once the point leaves the window; ignored with badge.followViewEdge (LiveChart only). Default false
}
interface MultiSeriesDotConfig extends DotConfig {
pulse?: boolean | PulseConfig;
valueLine?: boolean | ValueLineConfig;
valueLabel?: boolean;
}
interface LegendConfig {
visible?: boolean;
compact?: boolean;
position?: "top" | "bottom";
style?: LegendStyle;
}
interface FontConfig {
fontFamily?: string; // default "Menlo"
fontSize?: number; // default 11
fontWeight?: FontWeight;
typeface?: DataSourceParam; // require(...) / path / Uint8Array
fontManager?: SkFontMgr | null;
}
Imperative handle
LiveChart and LiveChartSeries accept a ref with the same exported handle:
interface LiveChartHandle {
// Reset built-in pinch zoom to timeWindow and clear its focal offset so the
// chart follows the live edge again. Safe when already reset.
resetZoom(): void;
}
useRef<LiveChartHandle>(null) and pass the ref to either chart. A paused chart remains paused.
See Time-scroll → Reset zoom from a button.
AxisLabelConfig
Shape for thetopLabel / bottomLabel props. Both are opt-in (default off).
With true, the chart floats its current top (topLabel) / bottom
(bottomLabel) Y-axis bound at that edge, formatted with format (falling back
to the chart’s formatValue) in color (falling back to the muted
palette.gridLabel), aligned by position. The values track the live Y-axis
range each frame on the UI thread. Set render to float a fully custom element
at the edge instead of the built-in value. position: "extrema" instead floats
the label (a dot + value, or your render element) at the actual data point
where the high / low occurs, tracking it as the chart scrolls. See
Axis labels and
Marking the extrema points.
SelectionDotProps
Props passed to a customselectionDot.component — the dot drawn at the scrub
intersection. Every positional input is a SharedValue, so the dot animates on
the UI thread without re-renders.
interface SelectionDotProps {
x: SharedValue<number>; // scrub X in canvas px
y: SharedValue<number>; // scrub Y (line / value intersection)
active: SharedValue<boolean>; // whether scrubbing is active
opacity: SharedValue<number>; // crosshair fade opacity (0..1), already ramped
color: string; // resolved dot color (line / series accent)
size: number; // suggested dot radius in px
}
TooltipRenderProps
Context passed to a customrenderTooltip — the fully custom scrub tooltip. The element you
return is a React Native view the chart floats over
the canvas and positions on the UI thread (per scrub.tooltipPlacement). Every live field is a
SharedValue, so bind them to animated text (e.g. an Animated.createAnimatedComponent(TextInput)
driven by useAnimatedProps) and both movement and text stay on the UI thread — no JS
re-render while scrubbing. See Custom tooltip.
interface TooltipRenderProps {
value: SharedValue<number | null>; // value under the crosshair (candle mode: the close)
time: SharedValue<number>; // window time (unix seconds) under the crosshair
valueStr: SharedValue<string>; // value formatted with the chart's formatValue
timeStr: SharedValue<string>; // time formatted with the chart's formatTime
active: SharedValue<boolean>; // whether scrubbing is active
// Candle mode: the OHLC bucket under the crosshair (null in line mode / inactive).
candle: SharedValue<CandlePoint | null>;
// Line or candle mode: the declared gap under the crosshair (null otherwise).
gap: SharedValue<ChartGap | null>;
}
ChartOverlayContext
The price↔pixel / time↔pixel bridge passed to a customrenderOverlay on LiveChart or
LiveChartSeries. It hands you a single per-frame scale SharedValue plus pure
mapping worklets.
interface ChartOverlayContext {
scale: SharedValue<ChartScale>; // live scale, recomputed each frame
priceToY: (price: number, scale: ChartScale) => number; // price → canvas Y px (-1 before layout)
yToPrice: (y: number, scale: ChartScale) => number | null; // canvas Y px → price (clamped; null before layout)
timeToX: (time: number, scale: ChartScale) => number; // unix seconds → canvas X px
xToTime: (x: number, scale: ChartScale) => number; // canvas X px → unix seconds
}
interface ChartScale {
min: number; // live Y-axis lower bound (price at the plot bottom)
max: number; // live Y-axis upper bound (price at the plot top)
window: number; // visible time window in seconds
now: number; // right-edge timestamp (unix seconds)
plot: ChartPlotRect;
}
interface ChartPlotRect {
left: number; // padding.left
top: number; // padding.top
right: number; // canvasWidth - padding.right
bottom: number; // canvasHeight - padding.bottom
width: number; // full canvas width
height: number; // full canvas height
}
usePriceY / useTimeX hooks. They project a price / time to
a SharedValue<number> that tracks the live axis for you. Render one component per
level and read the value in your useAnimatedStyle:
function PriceLevel({ ctx, price }) {
const y = usePriceY(ctx, price); // reactive — tracks the rescaling axis
const style = useAnimatedStyle(() => ({ transform: [{ translateY: y.get() }] }));
return <Animated.View style={style} />;
}
scale.get() inside your worklet — that read subscribes it to
the live scale — then feed the snapshot to the pure mappings. (Reanimated only
observes SharedValues read directly in a worklet’s closure, so the mappings take the
snapshot as an argument rather than reading it themselves.)
const style = useAnimatedStyle(() => {
const s = scale.get(); // subscribe to the live scale
const y = priceToY(142.5, s); // project a price level to its pixel
return { transform: [{ translateY: y }] };
});
DegenOptions
The most-used fields (see the source for the full tuning surface):interface DegenOptions {
scale?: number; // default 1
downMomentum?: boolean; // also trigger on down swings; default false
shake?: boolean; // default true
shakeIntensity?: number;
shakeDurationSec?: number; // default 0.45
burstParticleCount?: number; // default 20
particleOpacity?: number; // default 0.55
colors?: string | string[];
// ...plus particle slot/size/speed/jitter tuning
}
Palette
accentColor + theme derive a full LiveChartPalette. Override any subset via the palette
prop. Frequently overridden keys:
interface LiveChartPalette {
line: string;
fillTop: string; fillBottom: string;
gridLine: string; gridLabel: string;
dotUp: string; dotDown: string; dotFlat: string;
candleUp: string; candleDown: string; wickUp: string; wickDown: string;
dashLine: string; refLine: string; refLabel: string;
crosshairLine: string; crosshairDim: string;
tooltipBg: string; tooltipText: string; tooltipBorder: string;
// ...glow, badge, and font-size keys
}
Metrics
The geometry/motion analogue ofLiveChartPalette. Override any subset via the metrics prop
(per-namespace shallow merge — only the keys you set are replaced). See the
Theming guide.
interface LiveChartMetrics {
badge: BadgeMetrics;
candle: CandleMetrics;
grid: GridMetrics;
motion: MotionMetrics;
emptyState: EmptyStateMetrics;
}
interface BadgeMetrics {
padX: number; // pill horizontal padding, default 10
padY: number; // pill vertical padding, default 3
tailLength: number; // tail spike toward the dot, default 5
marginEdge: number; // gap from the canvas edge, default 4
dotGap: number; // gap between the dot and the tail tip, default 12
tailSpread: number; // tail curve control-point spread, default 2.5
}
interface CandleMetrics {
minBodyPx: number; // min body height so dojis stay visible, default 1
maxBodyPx: number; // max body width, default 40
bodyWidthRatio: number; // body width as a fraction of the slot, default 0.8
minGapPx: number; // min gap (px) between adjacent bodies; 0 = ratio-only, default 2
bodyRadius: number; // body corner radius (px); 0 = sharp, default 0
wickWidth: number; // wick (high–low line) stroke width (px), default 1
}
interface GridMetrics {
fadeInSpeed: number; // per-frame alpha lerp when a line/label fades in, default 0.18
fadeOutSpeed: number; // per-frame alpha lerp when it fades out, default 0.12
}
interface MotionMetrics {
badgeColorSpeed: number; // badge color transition lerp speed, default 0.08
adaptiveSpeedBoost: number; // extra catch-up over `smoothing` when the value lags, default 0.12
}
interface EmptyStateMetrics {
labelOpacity: number; // empty-state label opacity, default 0.35
gapPad: number; // half-padding around the empty text, default 20
gapFadeWidth: number; // fade width each side of the empty-text gap, default 30
}
// `metrics` prop type — every namespace and field optional:
type LiveChartMetricsOverride = {
badge?: Partial<BadgeMetrics>;
candle?: Partial<CandleMetrics>;
grid?: Partial<GridMetrics>;
motion?: Partial<MotionMetrics>;
emptyState?: Partial<EmptyStateMetrics>;
};