Package Exports
- funhi-chart
- funhi-chart/dist/index.esm.js
- funhi-chart/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (funhi-chart) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
FunhiChart 📊
A professional trading chart component for React applications. Display beautiful, interactive candlestick charts with real-time updates, multiple timeframes, and live market data.
Built with TradingView's Lightweight Charts library and optimized for crypto trading platforms.
🎯 What is FunhiChart?
FunhiChart is a React component that you can drop into any React application to display professional candlestick charts. It works everywhere:
- ✅ Create React App
- ✅ Next.js (App Router & Pages Router)
- ✅ Vite
- ✅ Remix
- ✅ Any React framework
Two Ways to Use:
- Standalone - Just pass a token address, and it displays a chart (perfect for demos or testing)
- Connected - Pass your own WebSocket connection and data for full real-time updates (production use)
⚡ Quick Start (30 seconds)
1. Install
npm install funhi-chart react react-dom lightweight-charts socket.io-client axios2. Use in Your App
import { FunhiChart } from 'funhi-chart';
function App() {
return (
<FunhiChart
mint="YourTokenMintAddress"
ticker="SOL"
tokenName="Solana"
/>
);
}That's it! 🎉 You now have a working chart.
📚 Complete Examples
Example 1: Basic Usage (Any React App)
Works in Create React App, Vite, or any React setup:
import React from 'react';
import { FunhiChart } from 'funhi-chart';
function TradingPage() {
return (
<div style={{ width: '100%', height: '600px' }}>
<FunhiChart
mint="SolTokenMintAddress"
ticker="SOL"
tokenName="Solana"
/>
</div>
);
}
export default TradingPage;Example 2: With Your Own WebSocket (Recommended)
Connect to your backend for real-time updates:
import React, { useState, useEffect } from 'react';
import { FunhiChart } from 'funhi-chart';
import { io } from 'socket.io-client';
function LiveChart() {
const [socket, setSocket] = useState(null);
const [connected, setConnected] = useState(false);
const [marketCap, setMarketCap] = useState(0);
useEffect(() => {
// Connect to your backend
const newSocket = io('https://your-backend.com');
newSocket.on('connect', () => setConnected(true));
newSocket.on('marketCap', (data) => setMarketCap(data.value));
setSocket(newSocket);
return () => newSocket.close();
}, []);
return (
<FunhiChart
mint="TokenAddress"
ticker="TOKEN"
tokenName="My Token"
// Connect to your WebSocket
socket={socket}
isConnected={connected}
currentMarketCap={marketCap}
/>
);
}Example 3: Next.js (App Router)
For Next.js, use dynamic import to avoid SSR issues:
'use client';
import dynamic from 'next/dynamic';
const FunhiChart = dynamic(
() => import('funhi-chart').then(mod => mod.FunhiChart),
{ ssr: false }
);
export default function ChartPage() {
return <FunhiChart mint="TokenAddress" ticker="SOL" />;
}Example 4: TypeScript
Full type safety with TypeScript:
import React from 'react';
import { FunhiChart, ChartProps } from 'funhi-chart';
import { Socket } from 'socket.io-client';
interface MyChartProps {
tokenAddress: string;
symbol: string;
socket?: Socket;
}
const MyChart: React.FC<MyChartProps> = ({ tokenAddress, symbol, socket }) => {
return (
<FunhiChart
mint={tokenAddress}
ticker={symbol}
socket={socket}
/>
);
};🎨 Features
- 🚀 Real-time Updates - Connect your WebSocket for live price updates
- 📊 Multiple Timeframes - 1m, 5m, 15m, 1h, 4h, 1d candlestick charts
- 🎨 Beautiful UI - Professional TradingView-style interface
- ⚡ High Performance - Handles thousands of data points smoothly
- 📱 Responsive - Works on mobile, tablet, and desktop
- 🎯 TypeScript - Full type definitions included
- 🔌 Flexible - Use standalone or with your own data
- 💾 Data Persistence - Automatic candle data caching
📖 API Reference
Props
All available props for the FunhiChart component:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
mint |
string |
✅ Yes | - | Token mint address (Solana address) |
ticker |
string |
No | "" |
Token symbol (e.g., "SOL", "BTC") |
tokenName |
string |
No | "" |
Full token name (e.g., "Solana") |
socket |
Socket |
No | null |
Your Socket.IO connection for live updates |
isConnected |
boolean |
No | false |
WebSocket connection status |
currentMarketCap |
number |
No | 0 |
Live market cap to display |
analyticsConnected |
boolean |
No | false |
Analytics connection status |
analyticsLoading |
boolean |
No | false |
Loading state for analytics |
TypeScript Types
import { Socket } from 'socket.io-client';
interface ChartProps {
// Required
mint: string;
// Optional - Display
ticker?: string;
tokenName?: string;
// Optional - Real-time Data
socket?: Socket | null;
isConnected?: boolean;
currentMarketCap?: number;
analyticsConnected?: boolean;
analyticsLoading?: boolean;
}Exports
// Main component
import { FunhiChart } from 'funhi-chart';
// TypeScript types
import type { ChartProps } from 'funhi-chart';
// Utility services (if needed)
import { candleStorageService, candleAggregation } from 'funhi-chart';🚀 Framework-Specific Guides
Create React App / Vite
Standard import works perfectly:
import { FunhiChart } from 'funhi-chart';
function App() {
return <FunhiChart mint="address" ticker="SOL" />;
}Next.js (Important!)
Next.js requires dynamic import with ssr: false because the chart uses browser APIs:
'use client';
import dynamic from 'next/dynamic';
const FunhiChart = dynamic(
() => import('funhi-chart').then(mod => mod.FunhiChart),
{ ssr: false, loading: () => <div>Loading...</div> }
);
export default function Page() {
return <FunhiChart mint="address" ticker="SOL" />;
}Remix
Use client-side only rendering:
import { ClientOnly } from 'remix-utils';
import { FunhiChart } from 'funhi-chart';
export default function Route() {
return (
<ClientOnly>
{() => <FunhiChart mint="address" ticker="SOL" />}
</ClientOnly>
);
}Gatsby
Use loadable-components or dynamic import in useEffect:
import React, { useEffect, useState } from 'react';
function ChartPage() {
const [Chart, setChart] = useState(null);
useEffect(() => {
import('funhi-chart').then(mod => setChart(() => mod.FunhiChart));
}, []);
if (!Chart) return <div>Loading...</div>;
return <Chart mint="address" ticker="SOL" />;
}💡 Common Use Cases
1. Quick Demo or Prototype
Just need a chart fast? One line does it:
<FunhiChart mint="SolanaTokenAddress" ticker="SOL" />2. Static Portfolio Tracker
Display charts for multiple tokens without live updates:
{tokens.map(token => (
<FunhiChart
key={token.mint}
mint={token.mint}
ticker={token.symbol}
tokenName={token.name}
/>
))}3. Live Trading Dashboard
Connect to your backend for real-time candle updates:
const { socket, connected } = useYourSocket();
<FunhiChart
mint={selectedToken}
ticker="BTC"
socket={socket}
isConnected={connected}
/>4. Full Analytics Platform
Pass all data for complete monitoring:
<FunhiChart
mint={token.mint}
ticker={token.symbol}
tokenName={token.name}
socket={websocket}
isConnected={socketStatus}
currentMarketCap={liveMarketCap}
analyticsConnected={analyticsStatus}
analyticsLoading={isLoading}
/>🔧 Advanced Features
Timeframe Switching
The chart includes built-in buttons to switch between timeframes:
- 1m - 1 minute candles
- 5m - 5 minute candles
- 15m - 15 minute candles
- 1h - 1 hour candles
- 4h - 4 hour candles
- 1d - 1 day candles
Users can click to switch anytime - the chart automatically aggregates data.
Data Persistence
Candle data is automatically saved to your backend database:
import { candleStorageService } from 'funhi-chart';
// Manually save candles (usually handled automatically)
await candleStorageService.saveCandles({
mint: 'your-token-mint',
candles: candleData,
timeFrame: 60 // 1 minute
});
// Retrieve candles
const candles = await candleStorageService.getCandles({
mint: 'your-token-mint',
timeFrame: 60,
limit: 1000
});Custom Aggregation
The chart includes utilities for aggregating 1-minute candles to larger timeframes:
import { candleAggregation, CandleData } from 'funhi-chart';
const oneMinuteCandles: CandleData[] = [...]; // Your 1m candle data
// Aggregate to 5-minute candles
const fiveMinuteCandles = candleAggregation.aggregateCandles(
oneMinuteCandles,
300 // 5 minutes in seconds
);
// Fill gaps in candle data
const filledCandles = candleAggregation.fillGaps(
fiveMinuteCandles,
300 // timeframe in seconds
);API Reference
Components
FunhiChart
Main chart component that displays real-time candlestick data.
<FunhiChart
mint="TokenMintAddress"
ticker="TOKEN"
tokenName="Token Name"
/>Hooks
useSocket
Hook for managing Socket.IO connections:
import { useSocket } from 'funhi-chart';
function MyComponent() {
const { socket, isConnected } = useSocket(socketInstance);
// Use socket connection
}useOptimizedTokenAnalytics
Hook for accessing token analytics data:
import { useOptimizedTokenAnalytics } from 'funhi-chart';
function MyComponent() {
const analytics = useOptimizedTokenAnalytics('token-mint', analyticsData);
console.log(analytics.currentPrice);
console.log(analytics.currentMarketCap);
}Services
candleStorageService
Service for managing candle data persistence:
import { candleStorageService } from 'funhi-chart';
// Save candles
await candleStorageService.saveCandles({
mint: 'token-mint',
candles: [...],
timeFrame: 60
});
// Get candles
const candles = await candleStorageService.getCandles({
mint: 'token-mint',
timeFrame: 60,
limit: 1000
});Utils
candleAggregation
Utility for aggregating candle data:
import { candleAggregation } from 'funhi-chart';
// Aggregate candles
const aggregated = candleAggregation.aggregateCandles(
oneMinuteCandles,
300 // target timeframe in seconds
);
// Fill gaps
const filled = candleAggregation.fillGaps(
candles,
300 // timeframe in seconds
);
// Get required candle count
const required = candleAggregation.getRequiredOneMinuteCandles(
3600, // 1 hour
1000 // target 1000 candles
);Backend Requirements
The chart component expects a backend API with the following endpoints:
Get Candles
GET /api/ohlcv/candles/:mint?timeFrame=60&limit=1000Response:
{
"success": true,
"data": {
"candles": [
{
"time": 1234567890,
"open": 100.5,
"high": 102.3,
"low": 99.8,
"close": 101.2,
"volume": 1500
}
]
}
}Save Candles
POST /api/ohlcv/candles/saveRequest body:
{
"mint": "token-mint-address",
"timeFrame": 60,
"candles": [...]
}WebSocket Events
The backend should support these Socket.IO events:
ohlcv:subscribe- Subscribe to OHLCV updatesohlcv:update- Receive candle updatesheartbeat- Receive periodic updateschartUpdate- Receive chart data updates
Styling
The chart uses Tailwind CSS classes. Make sure you have Tailwind CSS configured in your project, or provide custom CSS:
/* Custom styling example */
.chart-container {
width: 100%;
height: 600px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}Examples
Example 1: Basic Integration
import React from 'react';
import { FunhiChart } from 'funhi-chart';
export default function TradingPage() {
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Live Trading Chart</h1>
<FunhiChart
mint="YOUR_TOKEN_MINT_ADDRESS"
ticker="TOKEN"
tokenName="Your Token Name"
/>
</div>
);
}Example 2: With Custom Analytics
import React, { useState, useEffect } from 'react';
import { FunhiChart } from 'funhi-chart';
import axios from 'axios';
export default function AdvancedChart() {
const [analyticsData, setAnalyticsData] = useState(null);
useEffect(() => {
// Fetch analytics data from your API
async function fetchAnalytics() {
const response = await axios.get('/api/token/analytics');
setAnalyticsData(response.data);
}
fetchAnalytics();
}, []);
return (
<div className="w-full">
<FunhiChart
mint="YOUR_TOKEN_MINT_ADDRESS"
ticker="TOKEN"
tokenName="Your Token Name"
/>
{analyticsData && (
<div className="mt-4">
<h2>Token Analytics</h2>
{/* Display analytics data */}
</div>
)}
</div>
);
}Example 3: Multiple Charts
import React from 'react';
import { FunhiChart } from 'funhi-chart';
const tokens = [
{ mint: 'TOKEN1_MINT', ticker: 'TK1', name: 'Token 1' },
{ mint: 'TOKEN2_MINT', ticker: 'TK2', name: 'Token 2' },
{ mint: 'TOKEN3_MINT', ticker: 'TK3', name: 'Token 3' },
];
export default function MultiChart() {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
{tokens.map(token => (
<div key={token.mint} className="border rounded-lg p-4">
<h3 className="text-lg font-bold mb-2">{token.name}</h3>
<FunhiChart
mint={token.mint}
ticker={token.ticker}
tokenName={token.name}
/>
</div>
))}
</div>
);
}TypeScript Support
This package is written in TypeScript and includes type definitions:
import { FunhiChart, CandleData, TimeFrame } from 'funhi-chart';
const candle: CandleData = {
time: 1234567890,
open: 100,
high: 102,
low: 99,
close: 101,
volume: 1000
};
const timeFrame: TimeFrame = {
label: '1m',
value: '1m',
seconds: 60
};Performance Optimization
Tips for Optimal Performance
- Limit Data: Use the
limitparameter when fetching candles:
const candles = await candleStorageService.getCandles({
mint: 'token-mint',
timeFrame: 60,
limit: 500 // Limit to last 500 candles
});Debounce Updates: The chart automatically debounces real-time updates to prevent excessive re-renders.
Use Memoization: When passing data to the chart, use React.memo() or useMemo():
const ChartComponent = React.memo(() => (
<FunhiChart mint={mint} ticker={ticker} tokenName={tokenName} />
));❓ Frequently Asked Questions
Can I use this without Next.js?
Yes! FunhiChart works with any React application:
- Create React App ✅
- Vite ✅
- Remix ✅
- Gatsby ✅
- Plain React ✅
Only Next.js requires special handling (dynamic import with ssr: false).
Do I need a backend?
For basic use, no. The chart can work standalone with just a mint address.
For real-time updates, yes. You need:
- A WebSocket server (Socket.IO)
- An API that provides candle data
Can I use my own WebSocket connection?
Yes! Pass your socket as a prop:
<FunhiChart mint="address" socket={yourSocket} isConnected={true} />This is the recommended approach for production apps.
Does it work with non-Solana tokens?
The mint prop is designed for Solana token addresses, but you can pass any unique identifier. The chart itself is blockchain-agnostic - it just displays candlestick data.
Can I customize the appearance?
The chart has a professional design out of the box. The component itself doesn't expose styling props currently, but you can wrap it in a container with custom dimensions:
<div style={{ width: '100%', height: '600px', background: '#000' }}>
<FunhiChart mint="address" />
</div>How do I show real-time market cap?
Pass the currentMarketCap prop:
<FunhiChart
mint="address"
currentMarketCap={123456789}
analyticsConnected={true}
/>What's the difference between standalone and connected mode?
| Feature | Standalone | Connected |
|---|---|---|
| Setup | Just pass mint |
Pass socket and data props |
| Real-time updates | ❌ No | ✅ Yes |
| Live market cap | ❌ No | ✅ Yes |
| Connection badge | Shows "Disconnected" | Shows "Connected" |
| Best for | Demos, testing | Production apps |
Can I display multiple charts on one page?
Yes! Just render multiple components:
<FunhiChart mint="token1" ticker="SOL" />
<FunhiChart mint="token2" ticker="BTC" />
<FunhiChart mint="token3" ticker="ETH" />Each chart is independent.
Is TypeScript required?
No. The package works with JavaScript. TypeScript types are included as a bonus if you use TypeScript.
What license is this?
MIT License - free to use in commercial projects!
🐛 Troubleshooting
Chart shows "Disconnected" badge
This means no WebSocket is connected. Either:
- You're using standalone mode (expected behavior)
- Pass
socketandisConnectedprops for real-time mode
Next.js: "window is not defined" error
You forgot to use dynamic import! See the Next.js section.
Chart not displaying data
- Verify the
mintaddress is correct - Check browser console for API errors
- Ensure your backend API is running
- Check the API URL is configured correctly
Performance issues with multiple charts
Use virtualization or lazy loading:
import { lazy, Suspense } from 'react';
const FunhiChart = lazy(() => import('funhi-chart').then(m => ({ default: m.FunhiChart })));
<Suspense fallback={<Loading />}>
<FunhiChart mint="address" />
</Suspense>Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT © Funhi Team
Support
- Issues: GitHub Issues
- Email: support@funhi.com
- Documentation: Full Documentation
📝 Changelog
Version 1.0.0 (Current)
New Features:
- ✨ Component renamed to
FunhiChart(with backward compatibility) - 🔌 External socket prop support for seamless integration
- 📊 Live analytics props (market cap, connection status)
- 🎯 Works with any React framework
- ⚡ Production-ready with real-time updates
- 📱 Fully responsive design
- 🎨 Multiple timeframes (1m, 5m, 15m, 1h, 4h, 1d)
- 💾 Automatic data persistence
- 🎯 Full TypeScript support
Breaking Changes:
- None! Fully backward compatible with
FunhiChart
🙏 Credits
Built with:
- Lightweight Charts by TradingView
- Socket.IO for real-time communication
- React for UI
- Love ❤️ by the Funhi Team