Overview
Simple Charts is built as a modern React application with Chart.js for rendering, react-router-dom for routing, and a custom state persistence layer. The architecture follows a component-based design with clear separation of concerns.Technology Stack
- React 18: Component-based UI with hooks
- Chart.js 4: Canvas-based chart rendering
- react-chartjs-2: React wrapper for Chart.js
- react-router-dom: Client-side routing
- Tailwind CSS: Utility-first styling
- Vite: Build tool and dev server
Application Entry Point
The application initializes inmain.jsx:10-16:
Progressive Web App
Simple Charts registers as a PWA using Vite’s PWA plugin (main.jsx:8):
Routing Structure
The app usesreact-router-dom with three main routes defined in App.jsx:648-667:
| Route | Component | Purpose |
|---|---|---|
/ | ChartBuilderPage | Main chart creation interface |
/terms-and-conditions | TermsAndConditionsPage | Legal terms |
/privacy-policy | PrivacyPolicyPage | Privacy information |
* (catch-all) | Redirect to / | Handle unknown routes |
Component Hierarchy
Core Components
ChartBuilderPage
The main application component (App.jsx:256-634) manages:
- State: Chart data, options, and validation
- Persistence: Auto-save to localStorage
- Validation: Real-time data validation
- Export: PNG download functionality
AppShell
Layout wrapper (AppShell.jsx:5-46) providing:
- Application header with branding
- Theme toggle button
- Footer with legal links
- Consistent max-width container (
max-w-7xl)
DataTableEditor
Data input component (DataTableEditor.jsx:9-126):
- Label and value input fields
- Value mode selector (exact numbers vs percentages)
- Row add/remove/clear actions
- Real-time validation error display
ChartControlsPanel
Chart configuration component (ChartControlsPanel.jsx:26-215):
- Chart type selector (pie/bar)
- Title and axis labels
- Legend and value label toggles
- Color palette selection
- Advanced per-item color customization
ChartPreview
Chart rendering component (ChartPreview.jsx:31-67):
- Renders Pie or Bar chart using react-chartjs-2
- Displays validation issues when chart cannot render
- Uses
forwardRefto expose Chart.js instance for export
Chart.js Integration
Registration
Chart.js components and plugins are registered inChartPreview.jsx:19-29:
Font Configuration
Global font family set for all charts (ChartPreview.jsx:29):
Custom Plugin: valueOverlayPlugin
Custom Chart.js plugin (valueOverlayPlugin.js:1-98) that draws value labels directly on chart elements:
- Pie charts: Shows percentages at center of each slice
- Bar charts: Shows values above/below bars
- Localization: Supports Bengali numeral rendering
State Management
Application State Structure
The app uses a single state object (App.jsx:100-119):
State Hooks
usePersistedState
Custom hook for auto-saving state to localStorage (usePersistedState.js:7-45):
useTheme
Custom hook for dark/light mode (useTheme.js:18-35):
- Persists preference to localStorage (
"simple-charts:theme") - Detects system preference on first load
- Toggles
darkclass ondocument.documentElement
Data Flow
Update Flow
- User Input → Component event handler
- State Update →
setAppState()called - Persistence →
usePersistedStatesaves to localStorage (200ms debounce) - Validation →
validateRows()runs viauseMemo - Chart Update → Chart.js re-renders with new data
Validation Pipeline
validateRows() function (App.jsx:177-254) performs:
- Field Validation: Check required fields and number parsing
- Value Range: Validate percentages (0-100) if in percentage mode
- Chart-Specific: Pie chart rules (no negatives, at least one positive)
- Row Filtering: Only include complete, valid rows in chart
Computed Values
Several derived values useuseMemo for performance:
chartRows: Valid rows after validation (App.jsx:294)resolvedColors: Final colors with custom overrides (App.jsx:306-315)chartData: Chart.js data object (App.jsx:317-333)chartOptions: Chart.js configuration (App.jsx:340-486)
Internationalization
Bengali Numeral Support
The app automatically detects and preserves Bengali numerals (০-৯):- Input: Accepts both Latin (0-9) and Bengali digits
- Parsing: Normalizes to Latin for calculations (
normalizeNumericInput,App.jsx:51-59) - Display: Re-converts to Bengali if original input used Bengali (
formatChartNumber,App.jsx:73-83)
useBengaliNumerals flag) and passes this information to the chart for consistent display.
Export System
High-DPI Export
Charts export as PNG with configurable pixel ratios (App.jsx:21-25):
Export Process
- Preparation: Apply style overrides for consistent export colors
- Resize: Scale chart to high DPI using
devicePixelRatio - Render: Wait for Chart.js to re-render at high resolution
- Capture: Copy canvas to new canvas with background
- Download: Convert to blob and trigger browser download
- Restore: Reset chart to original DPI and styles
chartExport.js:91-147 for implementation details.
Performance Optimizations
Memoization
- All derived chart data uses
useMemoto prevent unnecessary recalculations - Validation only re-runs when rows or chart type changes
- Chart options object is memoized to prevent Chart.js re-renders
Debounced Persistence
usePersistedState debounces localStorage writes by 200ms (usePersistedState.js:33-39):
Animation Duration
Chart animations are kept short (350ms) for responsive feel (App.jsx:344-346):
Error Handling
Graceful Degradation
- localStorage errors are silently caught (quota exceeded, private mode)
- Invalid stored state falls back to default via
sanitizeState - Missing Chart.js canvas gracefully returns error message
User-Facing Validation
Two levels of validation issues:- Blocking Issues: Prevent chart rendering entirely
- Export Issues: Allow preview but block PNG export