Video Display Examples
Display videos with support for multiple sources, glob patterns, interactive scrubbing, and synchronization with charts.
Type Interface
import type { BaseChartProps, SortOrder } from '../../types';
export interface VideoSource {
src: string;
type?: string;
}
/**
* Event emitted when video state changes (scrubbing, playback, etc.)
* Follows the same pattern as ChartChangeEvent for consistency.
*/
export interface VideoChangeEvent {
/** Current frame number (0-indexed) */
frame: number;
/** Current time in seconds */
time: number;
/** Total duration in seconds */
duration: number;
/** Progress through video (0-1) */
progress: number;
/** Event type */
type: 'hover' | 'click' | 'scrub' | 'timeupdate' | 'play' | 'pause' | 'ended';
/** Whether video is currently playing */
isPlaying: boolean;
/** Native DOM event (if applicable) */
nativeEvent?: Event | MouseEvent;
}
export interface VideoProps extends BaseChartProps {
// Single source or pattern
src?: string;
sources?: VideoSource[];
// Glob pattern support
glob?: string;
sortOrder?: SortOrder;
// Video controls
controls?: boolean;
autoplay?: boolean;
loop?: boolean;
muted?: boolean;
preload?: 'auto' | 'metadata' | 'none';
// Appearance
poster?: string;
caption?: string;
// Frame rate (for frame calculations, defaults to 30)
fps?: number;
// Controlled mode - set current time externally
time?: number | null;
// Interactive scrubbing - enable mouse hover to scrub frames
enableScrubbing?: boolean;
// Use custom controls instead of native browser controls
customControls?: boolean;
// Snapshot URL function for efficient frame preview
snapshotUrl?: (frame: number) => string;
// Edge padding for custom controls (equal padding from left, right, and bottom)
edgePadding?: number;
// Marker styling
markerWidth?: number;
markerHeight?: number;
markerBottom?: number;
markerColor?: string;
// Unified change handler (similar to LineChart)
onChange?: (event: VideoChangeEvent) => void;
// Legacy callbacks (still supported)
onPlay?: () => void;
onPause?: () => void;
onEnded?: () => void;
onError?: () => void;
}
Basic Video Player
import { Video } from '@vuer-ai/vuer-viz';
export default function BasicVideoExample() {
return (
<Video
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
controls={true}
caption="Big Buck Bunny - Sample Video"
/>
);
}
Interactive Scrubbing & Chart Synchronization
Enable enableScrubbing to scrub through video frames by moving your mouse over the video. Use the onChange handler and time prop to synchronize with other components like LineChart.
Drag on video or hover over chart to scrub. Play video to see cursors follow.
import { useState } from 'react';
import { Video, LineChart, VerticalMarker, SeriesTooltip } from '@vuer-ai/vuer-viz';
import timeseriesData from './data/lissajous_timeseries.json';
import videoUrl from './data/lissajous_point.mp4';
// Use the generated timeseries data synchronized with the Lissajous video
const { metadata, series: rawSeries } = timeseriesData;
const fps = metadata.fps;
const series = rawSeries.map(s => ({
label: s.label,
x: s.x,
y: s.y,
color: s.color,
}));
export default function ScrubbingExample() {
const [time, setTime] = useState<number | null>(null);
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<Video
src={videoUrl}
width={500}
height={200}
fps={fps}
controls={true}
customControls={true}
enableScrubbing={true}
time={time}
markerColor="#3b82f6"
onChange={(e) => {
if (e.type === 'scrub' || e.type === 'timeupdate') {
setTime(e.time);
}
}}
caption="Lissajous Curve - Drag to scrub"
/>
<LineChart
series={series}
width={500}
height={200}
xLabel="Time (s)"
yLabel="Position"
onChange={(e) => e.type === 'hover' && setTime(e.x)}
>
<VerticalMarker x={time} color="#3b82f6" />
<SeriesTooltip x={time} series={series} />
</LineChart>
<p style={{ fontSize: '13px', color: '#888' }}>
Drag on video or hover over chart to scrub. Play video to see cursors follow.
</p>
</div>
);
}
VideoChangeEvent
The onChange handler receives a VideoChangeEvent with:
interface VideoChangeEvent { frame: number; // Current frame number (0-indexed) time: number; // Current time in seconds duration: number; // Total duration in seconds progress: number; // Progress through video (0-1) type: 'hover' | 'click' | 'scrub' | 'timeupdate' | 'play' | 'pause' | 'ended'; isPlaying: boolean; // Whether video is currently playing }
Controlled Mode
Pass a time prop to control the video position externally:
const [time, setTime] = useState(0); <Video src="video.mp4" time={time} onChange={(e) => setTime(e.time)} enableScrubbing /> <LineChart series={data} onChange={(e) => setTime(e.x)} > <VerticalMarker x={time} /> </LineChart>
Snapshot URL Support
For large videos or ML-generated content, provide a snapshotUrl function to display frame previews efficiently:
<Video src="video.mp4" enableScrubbing snapshotUrl={(frame) => `/api/frames/${videoId}/${frame}.jpg`} />
Glob Pattern Support
The Video component supports glob patterns for loading video sequences. This requires server-side implementation to resolve file paths.
import { Video } from '@vuer-ai/vuer-viz';
export default function GlobVideoExample() {
return (
<Video
glob="videos/*.mp4"
sortOrder="natural"
caption="Example: Video sequence from pattern"
/>
);
}
Features
- Standard HTML5 video controls
- Multiple source support (MP4, WebM, Ogg)
- Glob pattern support with sort options: natural, mtime, name, asc, desc
- Autoplay, loop, and muted options
- Poster image support
- Optional captions
- Interactive frame scrubbing with
enableScrubbing - Controlled mode with
timeprop for synchronization - Snapshot URL support for efficient frame preview
- onChange handler following LineChart's event pattern
- Playback event callbacks (onPlay, onPause, onEnded)
- Error handling