JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 28
  • Score
    100M100P100Q90866F
  • License MIT

FunhiChart - Professional real-time trading chart component powered by TradingView's Lightweight Charts with WebSocket support

Package Exports

  • funhi-chart
  • funhi-chart/package.json

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.

npm version License: MIT


🎯 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:

  1. Standalone - Just pass a token address, and it displays a chart (perfect for demos or testing)
  2. 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 axios

2. 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;

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=1000

Response:

{
  "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/save

Request body:

{
  "mint": "token-mint-address",
  "timeFrame": 60,
  "candles": [...]
}

WebSocket Events

The backend should support these Socket.IO events:

  • ohlcv:subscribe - Subscribe to OHLCV updates
  • ohlcv:update - Receive candle updates
  • heartbeat - Receive periodic updates
  • chartUpdate - 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

  1. Limit Data: Use the limit parameter when fetching candles:
const candles = await candleStorageService.getCandles({
  mint: 'token-mint',
  timeFrame: 60,
  limit: 500 // Limit to last 500 candles
});
  1. Debounce Updates: The chart automatically debounces real-time updates to prevent excessive re-renders.

  2. 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:

  1. You're using standalone mode (expected behavior)
  2. Pass socket and isConnected props 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

  1. Verify the mint address is correct
  2. Check browser console for API errors
  3. Ensure your backend API is running
  4. 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:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT © Funhi Team

Support

📝 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: