Create performant charts with zooming, panning and localization using D3.js in a WebView. Perfect for time-series data visualization with smooth interactions.
Interactive chart with zoom, pan, and multi-dataset support
- 📊 Multi-dataset support - Display multiple data series on the same chart
- 🔍 Zoom and pan - Interactive zooming and panning with smooth animations
- 🌍 Localization - Built-in support for different locales and custom calendar strings
- 🎨 Customizable styling - Full control over colors, margins, and appearance
- 📱 Cross-platform - Works seamlessly on iOS and Android
- ⚡ High performance - Leverages D3.js for smooth rendering of large datasets
- 🔧 Zero configuration - Assets are automatically bundled during installation
npm install @mitigate-dev/react-native-d3-chart
# or
yarn add @mitigate-dev/react-native-d3-chartNote: This library requires react-native-webview. If you don't have it installed:
npm install react-native-webview
# or
yarn add react-native-webviewimportReact,{useState,useMemo}from'react'import{View}from'react-native'importChartfrom'@mitigate-dev/react-native-d3-chart'exportdefaultfunctionApp(){const[width,setWidth]=useState(0)constheight=width*0.6// 16:10 aspect ratio// Generate some sample dataconstdatasets=useMemo(()=>[{measurementName: 'Temperature',color: '#e66',unit: '°C',decimals: 1,points: [{timestamp: Date.now()-3600000,value: 22.5},{timestamp: Date.now()-1800000,value: 23.1},{timestamp: Date.now(),value: 24.3},],},],[])consttimeDomain=useMemo(()=>({type: 'hour',start: Date.now()-3600000,// 1 hour agoend: Date.now(),}),[])constcolors={background: '#fff',highlightLine: '#000',border: '#555',cursorStroke: '#0ff',highlightLabel: '#000',highlightTime: '#444',}return(<Viewstyle={{flex: 1,padding: 20}}onLayout={(e)=>setWidth(e.nativeEvent.layout.width-40)}><Chartwidth={width}height={height}colors={colors}datasets={datasets}timeDomain={timeDomain}noDataString="No data available"/></View>)}💡 Want to see more? Check out the complete example app for advanced usage with multiple datasets, time domain switching, and interactive controls.
| Prop | Type | Required | Description |
|---|---|---|---|
width | number | ✅ | Chart width in pixels |
height | number | ✅ | Chart height in pixels |
datasets | Dataset[] | ✅ | Array of data series to display |
colors | ChartColors | ✅ | Color configuration for chart elements |
timeDomain | TimeDomain | ✅ | Control intial zoom level / scale of X-axis, doesn't have to fit the whole dataset |
noDataString | string | ✅ | Message to show when no data is available |
zoomEnabled | boolean | ❌ | Enable zoom guesture |
locale | string | ❌ | Locale for date/time formatting (default: 'en') |
marginHorizontal | number | ❌ | Horizontal margin in pixels |
highlightPosition | number | ❌ | Position of highlight line (0-1, default: 0.5 for center) |
highlightValuePosition | 'top' | 'tooltip' | 'none' | ❌ | Where to show values: header, floating tooltip, or hidden (default: 'top') |
xDividerConfig | XDividerConfig | ❌ | Style for vertical dividers on X axis (ticks or segments) |
errorSegments | ErrorSegment[] | ❌ | Time ranges with error messages to display |
calendarStrings | CalendarStrings | ❌ | Custom calendar strings for localization |
onZoomStarted | () => void | ❌ | Callback when zoom interaction starts |
onZoomEnded | () => void | ❌ | Callback when zoom interaction ends |
onHighlightChanged | (payload: HighlightPayload) => void | ❌ | Callback when highlight position changes with current values |
typeDataset={measurementName: string// Display name for this data seriescolor: string|ThresholdColor// Hex color for the line, or threshold-based coloringpoints: Point[]// Array of data pointsunit: string// Unit symbol (e.g., '°C', 'kg', 'm/s')decimals: number// Number of decimal places to showminDeltaY?: number// Minimum Y-axis change to show, limit Y-zoomareaColor?: string|null// Area fill color (null to disable, defaults to base color)axisColor?: string// Optional Y-axis text color (defaults to base color)slices?: Slices// Optional background regions/zonesdecimalSeparator?: '.'|','// Decimal separatordomain?: {// Custom Y-axis rangebottom: numbertop: number}}typeSlices={start: number// Start timestamp for the slicesend: number// End timestamp for the slicesitems: Array<{color: string// Background color (use alpha for transparency)start: {top: number;bottom: number}// Y-values at start timeend: {top: number;bottom: number}// Y-values at end time}>}typeThresholdColor={type: 'thresholds'baseColor: string// Default color for values below all thresholdsthresholds: Array<{value: number// Threshold valuecolor: string// Color to use above this value}>// Should be sorted by value descendinggradientBlur?: number// Gradient transition distance around thresholds. Default 0 - no blur}typePoint={timestamp: number// Unix timestamp in millisecondsvalue: number|null// Data value (null for gaps)}typeTimeDomain={type: string// Domain type (e.g., 'hour', 'day', 'week')start: number// Start timestamp (ms)end: number// End timestamp (ms)}typeChartColors={background: string// Chart background colorhighlightLine: string// Crosshair line colorborder: string// Chart border colorhighlightLabel: string// Value label text colorhighlightTime: string// Time label text colorcursorStroke: string// Cursor/crosshair circle color}typeCalendarStrings={days: string[]// Full day names (Sunday first)shortDays: string[]// Short day names (Sun first)months: string[]// Full month names (January first)shortMonths: string[]// Short month names (Jan first)}typeErrorSegment={message: string// Error message to displaymessageColor: string// Color for the error messagestart: number// Start timestamp (ms)end: number// End timestamp (ms)}// Option 1: Tick style (lines extending from labels)typeXDividerTick={type: 'tick'color?: string// Defaults to ChartColors.borderstrokeWidth?: number// Defaults to 0.5strokeDasharray?: string// Defaults to '2,2'}// Option 2: Segment style (alternating full-height segments)typeXDividerSegment={type: 'segment'variant?: 'hour'|'day'|{dynamicThreshold: number}// Defaults to dynamiccolor?: string// Defaults to '#FBFBFC' with gradient}typeXDividerConfig=XDividerTick|XDividerSegmenttypeHighlightPayload={timestamp: number// Exact timestamp at highlight positionvalues: Array<{value: number|null// Data value at this pointtimestamp: number// Point timestampcolor: string// Dataset colorerrorMessage: string|null// Error message if in error segmentmeasurementName: string// Dataset name}|null>// null if dataset has no data at this position}Control where the vertical highlight line appears and how values are displayed:
<Chart// ... other propshighlightPosition={0.7}// Position from 0 (left) to 1 (right), default: 0.5 (center)highlightValuePosition="tooltip"// 'top' (header), 'tooltip' (floating box), or 'none'onHighlightChanged={useCallback((payload)=>{console.log('Current timestamp:',payload.timestamp)console.log('Values:',payload.values)},[])}/>Highlight value position modes:
'top'(default): Shows values in the chart header area'tooltip': Displays a floating tooltip box near the highlight line'none': Hides value display, useful withonHighlightChangedfor custom UI
Customize the vertical grid lines on the X-axis:
// Dashed tick lines (default style)<ChartxDividerConfig={{type: 'tick',color: '#999',strokeWidth: 1,strokeDasharray: '4,4',}}/>// Alternating background segments<ChartxDividerConfig={{type: 'segment',variant: 'hour',// or 'day' or { dynamicThreshold: 95040000 }color: '#F5F5F5',}}/>Segment variants:
'hour': Every other hour has a background segment'day': Every other day has a background segment{ dynamicThreshold: number }: Auto-switches between hour/day based on visible time range
Display error messages and highlight problematic time ranges:
consterrorSegments=[{message: 'Sensor offline',messageColor: '#FF0000',start: Date.now()-3600000,end: Date.now()-1800000,},]<Chart// ... other propserrorSegments={errorSegments}/>Data points within error segments will show the error message instead of values, and the background will be highlighted.
constdatasets=[{measurementName: 'Temperature',color: '#e66',unit: '°C',decimals: 1,points: temperatureData,},{measurementName: 'Humidity',color: '#66e',unit: '%',decimals: 0,points: humidityData,},]Create dynamic line colors that change based on data values using threshold configurations. This is perfect for showing status indicators, alerts, or different states in your data:
constdatasetWithThresholds={measurementName: 'Server Load',unit: '%',decimals: 0,areaColor: '#e78e96',// Optional: custom area fill colorcolor: {type: 'thresholds',baseColor: '#00FF00',// Green for values below all thresholds (low load)gradientBlur: 5,// Smooth transition distance around thresholdsthresholds: [{value: 85,color: '#FF0000'},// Red for values >= 85% (critical){value: 50,color: '#FF9400'},// Orange for values >= 50% (warning)// Values < 50% will use baseColor (green)],},points: serverLoadData,}How it works:
- Thresholds should be sorted by value in descending order
- Values >= 85% will be colored red (
#FF0000) - critical load - Values >= 50% but < 80% will be colored orange (
#FF9400) - warning load - Values < 50% will use the
baseColorgreen (#00FF00) - healthy load - The
gradientBlurcreates smooth color transitions around threshold boundaries
Real-world examples:
- Temperature monitoring: Blue (cold) → Green (optimal) → Red (overheating)
- Performance metrics: Red (poor) → Yellow (acceptable) → Green (excellent)
- Battery levels: Red (critical) → Orange (low) → Green (healthy)
- Network latency: Green (fast) → Yellow (moderate) → Red (slow)
Add colored background regions to highlight acceptable ranges, warning zones, or targets:
constdatasetWithSlices={measurementName: 'CPU Usage',color: '#333',unit: '%',decimals: 1,points: cpuData,slices: {start: startTimestamp,end: endTimestamp,items: [{color: '#00FF0020',// Green with transparency (healthy zone)start: {bottom: 0,top: 50},end: {bottom: 0,top: 50},},{color: '#FFA50020',// Orange with transparency (warning zone)start: {bottom: 50,top: 80},end: {bottom: 50,top: 80},},{color: '#FF000020',// Red with transparency (critical zone)start: {bottom: 80,top: 100},end: {bottom: 80,top: 100},},],},}Features:
- Horizontal zones: Use same top/bottom values for start and end
- Diagonal zones: Use different values to create slanted regions
- Transparency: Use alpha channel (e.g.,
#FF000020) for subtle backgrounds - Multiple regions: Stack different colored zones for complex visualizations
<Chart// ... other propszoomEnabledonZoomStarted={()=>console.log('Zoom started')}onZoomEnded={()=>console.log('Zoom ended')}/>- React Native >= 0.60
- react-native-webview >= 11.0.0
- iOS 11.0+ / Android API 21+
- Error segment gradient: The gradient style for error segments is currently hardcoded and cannot be customized
- Highlight snap behavior: The snap-to-data-point logic (distance thresholds of 8 pixels and 10 minutes) is hardcoded and not configurable via props
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT
Made with create-react-native-library
