@rm-graph/react
v0.1.19
Published
RM-Graphs React - React components for RM-Graphs charting library
Maintainers
Readme
@rm-graph/react
RM-Graphs React - React components for RM-Graphs charting library.
Installation
npm install @rm-graph/react
scichartis automatically installed as a dependency!
Usage
import { Column3DChart, PRPDChart, TrendsChart } from '@rm-graph/react';
function App() {
const data = [[45, 1500, 1], [90, 2200, 2], [180, 1800, 3]];
return (
<Column3DChart
id="my-chart"
data={data}
height={400}
options={{
theme: 'dark',
xAxisTitle: 'Phase Angle (°)',
yAxisTitle: 'Amplitude (mVp)',
zAxisTitle: 'Cycle',
}}
onReady={(chart) => console.log('Chart ready!')}
/>
);
}Components
<Column3DChart />- 3D column charts<PRPDChart />- Phase Resolved Partial Discharge heatmap<TrendsChart />- Multi-series time trends<Surface3DChart />- 3D surface visualization
PRPDChart
The PRPDChart component displays Phase Resolved Partial Discharge data as an interactive heatmap.
Usage
import { PRPDChart } from '@rm-graph/react';
import type { PRPDDataPoint } from '@rm-graph/react';
function App() {
// Data format: [phaseAngle, amplitude, count][]
const prpdData: PRPDDataPoint[] = [
[45, 1500, 10], // 45° phase, 1500mV amplitude, 10 pulses
[90, 2200, 25], // 90° phase, 2200mV amplitude, 25 pulses
[180, -1800, 15], // 180° phase, -1800mV amplitude, 15 pulses
[270, -2500, 30], // 270° phase, -2500mV amplitude, 30 pulses
// ... more data points
];
return (
<PRPDChart
id="my-prpd-chart"
title="PRPD Analysis"
data={prpdData}
height={400}
scalingFactor={1}
unitOfMeasurement="mVp"
maxPeak={5000}
minPeak={-5000}
maxPhaseAngle={360}
showSineWave={true}
showColorPalette={true}
showMaximizeIcon={true}
colorMin={0}
colorMax={100}
onStatsChange={(stats) => console.log('Stats:', stats)}
/>
);
}PRPDDataPoint Type
type PRPDDataPoint = [number, number, number];
// [phaseAngle, amplitude, count]| Index | Type | Description |
|-------|------|-------------|
| 0 | number | Phase angle in degrees (0-360) |
| 1 | number | Amplitude value (positive or negative) |
| 2 | number | Pulse count at this phase/amplitude |
PRPDChart Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| id | string | auto-generated | Unique ID for the chart |
| title | string | - | Chart title displayed in header |
| data | PRPDDataPoint[] | [] | Array of [phase, amplitude, count] tuples |
| height | number \| string | 400 | Chart height |
| width | number \| string | '100%' | Chart width |
| scalingFactor | number | 1 | Multiplier for amplitude values |
| unitOfMeasurement | string | 'mVp' | Unit label for amplitude axis |
| maxPeak | number | 5000 | Maximum amplitude value |
| minPeak | number | -5000 | Minimum amplitude value |
| maxPhaseAngle | number | 360 | Maximum phase angle |
| yAxisRange | number | - | Y-axis visible range |
| showSineWave | boolean | true | Show sine wave overlay |
| showColorPalette | boolean | true | Show color legend bar |
| showToolbar | boolean | true | Show toolbar buttons |
| showMaximizeIcon | boolean | false | Show maximize button |
| isMaximized | boolean | false | Current maximized state |
| colorMin | number | 0 | Minimum color scale value |
| colorMax | number | 100 | Maximum color scale value |
| resolutionLabel | PRPDResolutionLabel | - | Resolution mode config |
| windowingData | PRPDWindowingRegion[] | - | Windowing filter regions |
Callbacks
| Prop | Type | Description |
|------|------|-------------|
| onReady | (chart) => void | Called when chart is initialized |
| onStatsChange | (stats) => void | Called when statistics update |
| onResolutionChange | (label) => void | Called when resolution mode changes |
| onWindowingClick | () => void | Called when windowing button clicked |
| onYAxisRangeChange | (range) => void | Called when Y-range changes |
| onMaximizeToggle | () => void | Called when maximize toggled |
Features
- 🎨 Heatmap Visualization - Color-coded pulse density display
- 📊 Color Palette Legend - Visual scale for pulse counts
- 〰️ Sine Wave Overlay - Reference waveform display
- 🔍 Zoom & Pan - Interactive data exploration
- 📏 Y-Range Control - Adjustable amplitude range (100-5000 or custom)
- 🔄 Resolution Modes - UNI/BI and HI/LO toggle options
- 🪟 Windowing Support - Filter specific phase/amplitude regions
- 📸 Screenshot - Export chart as PNG image
- 📈 Statistics - Real-time peak value and total count
TrendsChart
The TrendsChart component displays multiple time series with interactive features.
Usage
import { TrendsChart } from '@rm-graph/react';
import type { TrendLineData } from '@rm-graph/react';
function App() {
const trendsData: TrendLineData[] = [
{
name: 'Channel 1',
values: [150, 145, 160, 155, 148],
timestamps: [1707012000000, 1707012060000, 1707012120000, 1707012180000, 1707012240000],
color: '#3b82f6',
uom: 2,
},
{
name: 'Channel 2',
values: [100, 95, 110, 105, 98],
timestamps: [1707012000000, 1707012060000, 1707012120000, 1707012180000, 1707012240000],
color: '#ef4444',
uom: 2,
},
];
return (
<TrendsChart
id="my-trends-chart"
data={trendsData}
height={500}
showLegend={true}
showResetButton={true}
showPointMarkerToggle={true}
showOverview={true}
showScreenshotButton={true}
/>
);
}TrendLineData Interface
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| name | string | ✅ | Display name for the series (shown in legend) |
| values | number[] | ✅ | Array of numeric values (Y-axis data points) |
| timestamps | number[] | ✅ | Array of timestamps in milliseconds (X-axis data points) |
| color | string | ✅ | Line color (hex or CSS color, e.g., #3b82f6) |
| uom | number | ❌ | Optional unit of measurement code |
Note: The
valuesandtimestampsarrays must have the same length.
TrendsChart Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| id | string | auto-generated | Unique ID for the chart |
| data | TrendLineData[] | [] | Array of trend line data |
| height | number \| string | 400 | Chart height |
| xAxisTitle | string | "Time (HH:MM)" | X-axis title |
| yAxisTitle | string | Based on chartType | Y-axis title |
| showLegend | boolean | true | Show interactive legend |
| showResetButton | boolean | true | Show reset zoom button |
| showPointMarkerToggle | boolean | true | Show point marker toggle |
| showOverview | boolean | true | Show overview mini-map |
| showScreenshotButton | boolean | true | Show screenshot button |
| onScreenshot | () => void | - | Callback when screenshot is taken |
Features
- 📊 Interactive Legend - Click to toggle series visibility
- 🔍 Zoom & Pan - Rubber band zoom, mouse wheel zoom, drag to pan
- 🔄 Reset Zoom - One-click reset to initial view
- 📍 Point Markers - Toggle visibility of data point markers
- 🗺️ Overview Chart - Mini-map for navigation
- 📸 Screenshot - Export chart as PNG with header
- 📅 Custom Date Labels - Formatted as DD/MM/YYYY HH:MM
Hooks
import { useChart } from '@rm-graph/react';
import { createColumn3DChart } from '@rm-graph/core';
function CustomChart() {
const { containerRef, chart, isLoading } = useChart({
config: { data: [...] },
createChart: createColumn3DChart,
});
return <div ref={containerRef} />;
}🔑 SciChart License Configuration
This package uses SciChart.js, which requires a valid license key to remove watermarks. The license system supports encrypted storage and multiple configuration methods.
Complete License Flow
Step 1: Get Your SciChart License Key
- Register your domain at SciChart License Portal
- Add allowed domains to your license:
- For production:
yourdomain.com,app.yourdomain.com - For development:
localhost,127.0.0.1, or your local IP (e.g.,192.168.140.16)
- For production:
- Copy your license key (format:
xxxx-xxxx-xxxx-xxxx)
Important: SciChart licenses are domain-locked. Make sure to register all domains where you'll use the charts.
Step 2: Configure License in Your App
You have three options to configure the license:
Option A: Using LicenseManager Component (Recommended for User-Facing Apps)
Add the LicenseManager component to your settings page:
import { useState } from 'react';
import { LicenseManager } from '@rm-graph/react';
import type { LicenseStatus } from '@rm-graph/react';
function SettingsPage() {
const [showLicense, setShowLicense] = useState(false);
const handleLicenseChange = (status: LicenseStatus) => {
console.log('License status:', status);
// Don't auto-close - let user see success message and click Reload
};
return (
<div>
<button onClick={() => setShowLicense(!showLicense)}>
🔑 License Settings
</button>
{showLicense && (
<LicenseManager
onLicenseChange={handleLicenseChange}
title="SciChart License Configuration"
placeholder="Paste your SciChart license key here"
theme="light"
/>
)}
</div>
);
}User Flow:
- User opens settings page
- User enters SciChart license key in the input field
- User clicks "Save License"
- License is encrypted and stored in localStorage
- License is immediately applied to SciChart
- User may need to reload page for existing charts to pick up the license
Option B: Programmatic Setup (For Admin/Backend Configuration)
// In your app entry point (main.tsx or App.tsx)
import { loadLicense, setLicense } from '@rm-graph/react';
// Load existing license on app startup
async function initializeApp() {
const loaded = await loadLicense();
if (loaded) {
console.log('License loaded from storage');
} else {
console.log('No license found - charts will show watermark');
}
// Render your app
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
}
initializeApp();
// To set a license programmatically:
async function configureLicense(licenseKey: string) {
const success = await setLicense(licenseKey);
if (success) {
console.log('License saved and applied!');
}
}Option C: Environment Variable (For Build-Time Configuration)
# .env file
VITE_SCICHART_LICENSE_KEY=your-license-key-here// main.tsx
import { setupSciChartLicense } from '@rm-graph/react';
// This will automatically read from VITE_SCICHART_LICENSE_KEY
setupSciChartLicense({
fromEnv: true,
fromLocalStorage: true, // Also check encrypted storage
});Step 3: License Storage & Security
The license system provides encrypted storage for security:
- Encryption: License keys are encrypted using AES-256-GCM (when Web Crypto API is available) or base64 encoding (fallback)
- Storage: Encrypted license is stored in
localStorageunder keyRMGRAPH_LICENSE_DATA - Security Note: While encrypted, this provides obfuscation rather than true security since decryption happens client-side. For production, combine with SciChart's domain-locking.
Storage Flow:
User enters license → Encrypt → Store in localStorage → Decrypt on load → Apply to SciChartStep 4: Verify License is Working
After configuring the license:
- Check browser console - Should see no license errors
- Check charts - Should render without "SCICHART" watermark
- Check license status:
import { getLicenseStatus, hasStoredLicense, isLicenseApplied } from '@rm-graph/react';
const status = getLicenseStatus();
console.log('Has license stored:', status.hasLicense);
console.log('License applied:', status.isApplied);
// Or use individual functions
if (hasStoredLicense()) {
console.log('License exists in storage');
}
if (isLicenseApplied()) {
console.log('License is active');
}LicenseManager Component API
The LicenseManager component provides a complete UI for license management:
Features:
- ✅ Status indicator (green/red dot) showing license state
- ✅ Password-masked input field for secure key entry
- ✅ Save/Remove license buttons
- ✅ Success message ("License saved successfully!")
- ✅ Reload notice with "Reload Now" button
- ✅ Error messages for validation failures
- ✅ Light/Dark theme support
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onLicenseChange | (status: LicenseStatus) => void | - | Callback when license status changes |
| className | string | - | Custom CSS class name |
| style | React.CSSProperties | - | Custom inline styles |
| title | string | "SciChart License Configuration" | Title text |
| placeholder | string | "Paste your SciChart license key here" | Input placeholder |
| successMessageDuration | number | 2000 | Success message display duration (ms) |
| autoLoad | boolean | true | Auto-load license on mount |
| requireReload | boolean | true | Show reload notice after license change |
| theme | 'light' \| 'dark' | 'light' | Component theme |
License Management Functions
import {
// Configuration
configureLicenseEncryption,
// License operations
setLicense, // Save and apply license
loadLicense, // Load from storage and apply
removeLicense, // Remove stored license
applyLicenseKey, // Apply directly without storing
// Status checks
hasStoredLicense, // Check if license exists in storage
isLicenseApplied, // Check if license is active
getLicenseStatus, // Get full status object
validateLicenseFormat, // Validate key format
// Types
type LicenseStatus,
type LicenseConfig,
} from '@rm-graph/react';Complete Example: Full License Setup
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { loadLicense } from '@rm-graph/react';
import App from './App';
// Load license on app startup
async function init() {
await loadLicense();
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
}
init();// App.tsx
import { useState } from 'react';
import { LicenseManager, Column3DChart } from '@rm-graph/react';
import type { LicenseStatus } from '@rm-graph/react';
function App() {
const [showLicenseManager, setShowLicenseManager] = useState(false);
const handleLicenseChange = (status: LicenseStatus) => {
console.log('License status:', status);
// Don't auto-close - let user see success message and click Reload Now button
};
return (
<div>
<header>
<h1>My Chart App</h1>
<button onClick={() => setShowLicenseManager(!showLicenseManager)}>
🔑 License Settings
</button>
</header>
{showLicenseManager && (
<LicenseManager
onLicenseChange={handleLicenseChange}
title="SciChart License Configuration"
placeholder="Paste your SciChart license key here"
theme="light"
/>
)}
<Column3DChart
id="my-chart"
data={[[45, 1500, 1], [90, 2200, 2]]}
height={400}
/>
</div>
);
}Troubleshooting
Issue: "License key is not valid for this domain"
Cause: Your license key is registered for a different domain than where you're accessing the app.
Solutions:
- Check your registered domains in SciChart portal
- Add the current domain to your license:
- For localhost: Add
localhostand127.0.0.1 - For IP access: Add your IP (e.g.,
192.168.140.16) - For production: Add your production domain
- For localhost: Add
- Access via registered domain: Use the exact domain/IP you registered
Issue: "Failed to save license" / Crypto errors
Cause: Web Crypto API is not available (requires HTTPS or localhost).
Solutions:
- Use HTTPS: Deploy with SSL certificate
- Use localhost: Access via
http://localhost:PORTinstead of IP - The system will automatically fallback to base64 encoding (less secure but functional)
Issue: Charts still show watermark after setting license
Solutions:
- Reload the page - Existing charts need to be recreated with the license
- Check license status:
getLicenseStatus()to verify it's applied - Check browser console for license errors
- Verify domain matches your registered license
Issue: License works on localhost but not on IP
Cause: SciChart licenses are domain-specific.
Solutions:
- Register both domains: Add both
localhostAND your IP to the license - Use consistent access method: Always use the same URL format
- For development: Consider using
localhostonly
Security Best Practices
- Domain Locking: Always register specific domains in SciChart portal
- Environment Variables: Use
.envfiles for build-time configuration (never commit keys) - HTTPS: Use HTTPS in production for secure crypto operations
- User Input: If allowing users to enter licenses, validate format before saving
- Storage: Encrypted storage provides obfuscation, not true security (decryption is client-side)
License Status Types
interface LicenseStatus {
/** Whether a license is stored in localStorage */
hasLicense: boolean;
/** Whether the license was successfully applied to SciChart */
isApplied: boolean;
/** Error message if license operation failed */
error?: string;
}See main README for full documentation.
