Skip to content

Repository files navigation

@mitigate-dev/react-native-d3-chart

Create performant charts with zooming, panning and localization using D3.js in a WebView. Perfect for time-series data visualization with smooth interactions.

Preview

Demo

Interactive chart with zoom, pan, and multi-dataset support

Features

  • 📊 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

Installation

npm install @mitigate-dev/react-native-d3-chart
# or
yarn add @mitigate-dev/react-native-d3-chart

Note: This library requires react-native-webview. If you don't have it installed:

npm install react-native-webview
# or
yarn add react-native-webview

Quick Start

importReact,{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.

API Reference

Chart Props

PropTypeRequiredDescription
widthnumberChart width in pixels
heightnumberChart height in pixels
datasetsDataset[]Array of data series to display
colorsChartColorsColor configuration for chart elements
timeDomainTimeDomainControl intial zoom level / scale of X-axis, doesn't have to fit the whole dataset
noDataStringstringMessage to show when no data is available
zoomEnabledbooleanEnable zoom guesture
localestringLocale for date/time formatting (default: 'en')
marginHorizontalnumberHorizontal margin in pixels
highlightPositionnumberPosition 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')
xDividerConfigXDividerConfigStyle for vertical dividers on X axis (ticks or segments)
errorSegmentsErrorSegment[]Time ranges with error messages to display
calendarStringsCalendarStringsCustom calendar strings for localization
onZoomStarted() => voidCallback when zoom interaction starts
onZoomEnded() => voidCallback when zoom interaction ends
onHighlightChanged(payload: HighlightPayload) => voidCallback when highlight position changes with current values

Types

Dataset

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}

Point

typePoint={timestamp: number// Unix timestamp in millisecondsvalue: number|null// Data value (null for gaps)}

TimeDomain

typeTimeDomain={type: string// Domain type (e.g., 'hour', 'day', 'week')start: number// Start timestamp (ms)end: number// End timestamp (ms)}

ChartColors

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}

CalendarStrings

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)}

ErrorSegment

typeErrorSegment={message: string// Error message to displaymessageColor: string// Color for the error messagestart: number// Start timestamp (ms)end: number// End timestamp (ms)}

XDividerConfig

// 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|XDividerSegment

HighlightPayload

typeHighlightPayload={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}

Advanced Usage

Highlight Position and Value Display

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 with onHighlightChanged for custom UI

X-Axis Dividers

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

Error Segments

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.

Multiple Datasets

constdatasets=[{measurementName: 'Temperature',color: '#e66',unit: '°C',decimals: 1,points: temperatureData,},{measurementName: 'Humidity',color: '#66e',unit: '%',decimals: 0,points: humidityData,},]

Threshold-Based Colors

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 baseColor green (#00FF00) - healthy load
  • The gradientBlur creates 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)

Background Slices/Zones

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

Zoom Callbacks

<Chart// ... other propszoomEnabledonZoomStarted={()=>console.log('Zoom started')}onZoomEnded={()=>console.log('Zoom ended')}/>

Requirements

  • React Native >= 0.60
  • react-native-webview >= 11.0.0
  • iOS 11.0+ / Android API 21+

Known Limitations

  • 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

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

MIT


Made with create-react-native-library

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages