https://github.com/dsnchz/solid-uplot
SolidJS wrapper for uPlot — an ultra-fast, tiny time-series & charting library with a SolidJS enhanced plugin system
https://github.com/dsnchz/solid-uplot
analysis canvas canvas-chart canvas-chart-library charting-library charts data-analysis data-analytics data-visualization solidjs trading visualization
Last synced: 3 months ago
JSON representation
SolidJS wrapper for uPlot — an ultra-fast, tiny time-series & charting library with a SolidJS enhanced plugin system
- Host: GitHub
- URL: https://github.com/dsnchz/solid-uplot
- Owner: dsnchz
- License: mit
- Created: 2025-05-13T15:41:45.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-06-17T15:17:52.000Z (7 months ago)
- Last Synced: 2025-10-10T22:14:27.242Z (3 months ago)
- Topics: analysis, canvas, canvas-chart, canvas-chart-library, charting-library, charts, data-analysis, data-analytics, data-visualization, solidjs, trading, visualization
- Language: TypeScript
- Homepage:
- Size: 267 KB
- Stars: 14
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# @dschz/solid-uplot
[](LICENSE)
[](https://github.com/leeoniya/uPlot)
[](https://www.npmjs.com/package/@dschz/solid-uplot)
[](https://bundlephobia.com/package/@dschz/solid-uplot)
[](https://jsr.io/@dschz/solid-uplot)
[](https://github.com/dsnchz/solid-uplot/actions/workflows/ci.yaml)
[](https://discord.gg/6wkpXQCNn6)
> 💹 SolidJS wrapper for [uPlot](https://github.com/leeoniya/uPlot) — an ultra-fast, small footprint charting library for time-series data.
## ✨ Features
- ✅ Fully reactive SolidJS wrapper around uPlot
- 🔌 Plugin system support with inter-plugin communication
- 🎯 Fine-grained control over chart lifecycle
- 💡 Lightweight and fast
- 💻 TypeScript support out of the box
- 🎨 Built-in plugins for tooltips, legends, cursor tracking, and series focusing
- 📱 Responsive sizing support with auto-resize capabilities
## 📦 Installation
```bash
npm install solid-js uplot @dschz/solid-uplot
pnpm install solid-js uplot @dschz/solid-uplot
yarn install solid-js uplot @dschz/solid-uplot
bun install solid-js uplot @dschz/solid-uplot
```
## 📁 Package Structure
This package provides three main export paths for different functionality:
### `@dschz/solid-uplot`
Core components and plugin system:
```tsx
import { SolidUplot, createPluginBus } from "@dschz/solid-uplot";
import type {
SolidUplotPluginBus,
UplotPluginFactory,
UplotPluginFactoryContext,
} from "@dschz/solid-uplot";
```
### `@dschz/solid-uplot/plugins`
This export path provides four plugins (three of which can be considered primitives).
- `cursor`: transmits cursor position data
- `focusSeries`: transmits which series are visually emphasized
- `tooltip`: plugin that allows you to present a custom JSX tooltip around the cursor
- `legend`: plugin that allows you to present a custom JSX component as your legend over the canvas drawing area.
```tsx
import { cursor, tooltip, legend, focusSeries } from "@dschz/solid-uplot/plugins";
import type {
CursorPluginMessageBus,
FocusSeriesPluginMessageBus,
TooltipProps,
LegendProps,
} from "@dschz/solid-uplot/plugins";
```
### `@dschz/solid-uplot/utils`
Some convenience utility functions for getting certain bits of data from a `uPlot` instance (except for `getColorString` which translates a series' `stroke` or `fill` into a color value).
```tsx
import {
getSeriesData,
getCursorData,
getColorString,
getNewCalendarDayIndices,
} from "@dschz/solid-uplot/utils";
import type { SeriesDatum, CursorData } from "@dschz/solid-uplot/utils";
```
## 🚀 Quick Start
```tsx
import { SolidUplot, createPluginBus } from "@dschz/solid-uplot";
import { cursor, tooltip, legend } from "@dschz/solid-uplot/plugins";
import type { CursorPluginMessageBus, TooltipProps, LegendProps } from "@dschz/solid-uplot/plugins";
// Create a tooltip component
const MyTooltip = (props: TooltipProps) => (
X: {props.cursor.xValue}
{(series) => {
const value = props.u.data[series.seriesIdx]?.[props.cursor.idx];
return (
{series.label}: {value}
);
}}
);
// Create a legend component
const MyLegend = (props: LegendProps) => (
{(series) => (
{series.label}
)}
);
const MyChart = () => {
const bus = createPluginBus();
return (
);
};
```
## 📏 Responsive Sizing
For responsive charts that automatically adapt to container size changes, use the `autoResize` prop:
```tsx
```
For more advanced responsive patterns, you can pair this library with [@dschz/solid-auto-sizer](https://github.com/dsnchz/solid-auto-sizer):
```bash
npm install @dschz/solid-auto-sizer
pnpm install @dschz/solid-auto-sizer
yarn install @dschz/solid-auto-sizer
bun install @dschz/solid-auto-sizer
```
```tsx
import { AutoSizer } from "@dschz/solid-auto-sizer";
{({ width, height }) => }
;
```
## 🔌 Enhanced Plugin System
The cornerstone feature of `SolidUplot` is its refined plugin system that enables extensible functionality and inter-plugin communication through a reactive message bus.
### Plugin Bus Architecture
The Plugin Bus System enables plugins to communicate with each other and external components through a reactive store. This architecture provides:
- **Type-safe communication**: All plugin messages are fully typed
- **Reactive updates**: Changes in plugin state automatically trigger updates
- **Decoupled components**: Plugins can interact without direct dependencies
- **Extensible**: Easy to add new plugins that integrate with existing ones
### Built-in Plugins
#### Cursor Plugin
Tracks cursor position and interaction state across charts:
```tsx
import { cursor } from "@dschz/solid-uplot/plugins";
import type { CursorPluginMessageBus } from "@dschz/solid-uplot/plugins";
const cursorPlugin = cursor();
```
The cursor plugin provides cursor position data that other plugins can consume through the bus.
#### Focus Series Plugin
Highlights series based on cursor proximity:
```tsx
import { focusSeries } from "@dschz/solid-uplot/plugins";
import type { FocusSeriesPluginMessageBus } from "@dschz/solid-uplot/plugins";
const focusPlugin = focusSeries({
pxThreshold: 15, // Distance threshold for focusing (default: 15)
});
```
#### Tooltip Plugin
Renders custom tooltips with automatic positioning and overflow handling:
```tsx
import { tooltip } from "@dschz/solid-uplot/plugins";
import type { TooltipProps } from "@dschz/solid-uplot/plugins";
const MyTooltip: Component = (props) => {
return (
X: {props.cursor.xValue}
{(series) => {
const value = () => props.u.data[series.seriesIdx]?.[props.cursor.idx];
return (
{series.label}: {value()?.toFixed(2)}
);
}}
);
};
const tooltipPlugin = tooltip(MyTooltip, {
placement: "top-left", // "top-left" | "top-right" | "bottom-left" | "bottom-right"
zIndex: 20,
});
```
#### Legend Plugin
Adds customizable legends with smart positioning and interactive features:
```tsx
import { legend } from "@dschz/solid-uplot/plugins";
import type { LegendProps } from "@dschz/solid-uplot/plugins";
const MyLegend: Component = (props) => {
// Access cursor data for interactive features
const cursorVisible = () => props.bus.data.cursor?.state[props.u.root.id]?.visible;
return (
Legend
{(series) => (
{series.label}
)}
);
};
const legendPlugin = legend(MyLegend, {
placement: "top-left", // "top-left" | "top-right"
pxOffset: 8, // Distance from chart edges (default: 8)
zIndex: 10,
});
```
**Legend Plugin Features:**
- **Simple positioning**: Only top-left or top-right corners to avoid axis conflicts
- **Size-constrained**: Legend cannot exceed chart drawing area dimensions
- **Layout-agnostic**: You control internal layout and styling
- **Non-interfering**: Designed to work harmoniously with chart interactions
- **Plugin bus integration**: Access cursor and focus data for smart interactions
- **Automatic cleanup**: Proper memory management and DOM cleanup
### Plugin Bus Type Safety
When using multiple plugins, ensure type safety by properly typing the plugin bus:
```tsx
import { createPluginBus } from "@dschz/solid-uplot";
import type {
CursorPluginMessageBus,
FocusSeriesPluginMessageBus,
} from "@dschz/solid-uplot/plugins";
// Create a bus that includes all plugin message types
const bus = createPluginBus();
const MyChart = () => {
return (
);
};
```
### Creating Custom Plugins
The plugin system is open to extension. When authoring plugins for public consumption, follow this pattern:
```tsx
import type { UplotPluginFactory } from "@dschz/solid-uplot";
import type { CursorPluginMessageBus } from "@dschz/solid-uplot/plugins";
// 1. Define your plugin's message type
export type MyPluginMessage = {
value: number;
timestamp: number;
};
// 2. Define your plugin's message bus
export type MyPluginMessageBus = {
myPlugin?: MyPluginMessage;
};
// 3. Export your plugin factory
export const myPlugin = (
options = {},
): UplotPluginFactory => {
return ({ bus }) => {
if (!bus) {
console.warn("[my-plugin]: A plugin bus is required");
return { hooks: {} };
}
return {
hooks: {
ready: (u) => {
// Initialize plugin state
bus.setData("myPlugin", {
value: 0,
timestamp: Date.now(),
});
},
setData: (u) => {
// Update plugin state
bus.setData("myPlugin", "value", (prev) => prev + 1);
},
},
};
};
};
```
### External Component Integration
The plugin bus enables powerful integrations between charts and external components:
```tsx
import { createPluginBus } from "@dschz/solid-uplot";
import type { FocusSeriesPluginMessageBus } from "@dschz/solid-uplot/plugins";
const bus = createPluginBus();
// External component that can trigger series focus
const DataGrid = (props: { bus: typeof bus }) => {
const handleRowHover = (seriesLabel: string) => {
props.bus.setData("focusSeries", {
sourceId: "data-grid",
targets: [{ label: seriesLabel }],
});
};
return {/* Grid implementation */};
};
// Chart and grid interact through shared bus
const MyDashboard = () => {
return (
);
};
```
## 🔧 API Reference
### SolidUplot Component
```tsx
type SolidUplotEvents = {
/** Callback fired when the uPlot instance is created */
readonly onCreate?: (u: uPlot, meta: OnCreateMeta) => void;
/** Callback fired when the cursor moves */
readonly onCursorMove?: (params: OnCursorMoveParams) => void;
};
// Main component props (extends all uPlot.Options except plugins, width, height)
type SolidUplotProps = SolidUplotOptions &
SolidUplotEvents & {
// Ref callback to access the chart container element
ref?: Ref;
// CSS class name for the chart container (default: "solid-uplot")
// Additional classes will be appended to the default class
class?: string;
// CSS styles for the chart container (position is managed internally)
style?: Omit;
// Enable automatic resizing to fit container (default: false)
autoResize?: boolean;
// Whether to reset scales when chart data is updated (default: true)
resetScales?: boolean;
// Where to place children components relative to the chart (default: "top")
childrenPlacement?: "top" | "bottom";
};
// Configuration options extending uPlot.Options with SolidJS enhancements
type SolidUplotOptions = Omit<
uPlot.Options,
"plugins" | "width" | "height"
> & {
// Chart dimensions
width?: number; // default: 600
height?: number; // default: 300
// Plugin configuration
plugins?: SolidUplotPlugin[];
pluginBus?: SolidUplotPluginBus;
};
// Plugin type (can be standard uPlot plugin or factory function)
type SolidUplotPlugin = uPlot.Plugin | UplotPluginFactory;
```
### Plugin Bus
```tsx
// Plugin bus type (derived from createPluginBus return type)
type SolidUplotPluginBus = ReturnType>;
// Create a plugin bus
const createPluginBus: (
initialData?: T,
) => SolidUplotPluginBus;
```
### Built-in Plugin Options
```tsx
// Cursor Plugin
const cursor = (): UplotPluginFactory;
// Focus Series Plugin
const focusSeries = (options?: {
pxThreshold?: number; // default: 15
}): UplotPluginFactory;
// Tooltip Plugin
const tooltip = (
Component: Component,
options?: {
placement?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
id?: string;
class?: string;
style?: JSX.CSSProperties;
zIndex?: number; // default: 20
}
): UplotPluginFactory;
// Legend Plugin
const legend = (
Component: Component,
options?: {
placement?: "top-left" | "top-right"; // default: "top-left"
pxOffset?: number; // default: 8
id?: string;
class?: string;
style?: JSX.CSSProperties;
zIndex?: number; // default: 10
}
): UplotPluginFactory;
```
## 📚 Examples
### Basic Chart
```tsx
import { SolidUplot } from "@dschz/solid-uplot";
const BasicChart = () => {
return (
);
};
```
### Chart with All Plugins
```tsx
import { SolidUplot, createPluginBus } from "@dschz/solid-uplot";
import { cursor, tooltip, legend, focusSeries } from "@dschz/solid-uplot/plugins";
import type {
CursorPluginMessageBus,
FocusSeriesPluginMessageBus,
TooltipProps,
LegendProps,
} from "@dschz/solid-uplot/plugins";
const MyTooltip: Component = (props) => (
Time: {new Date(props.cursor.xValue * 1000).toLocaleTimeString()}
{(series) => {
const value = props.u.data[series.seriesIdx]?.[props.cursor.idx];
return (
{series.label}: {value?.toFixed(2)}
);
}}
);
const MyLegend: Component = (props) => {
const cursorVisible = () => props.bus.data.cursor?.state[props.u.root.id]?.visible;
return (
{(series) => (
{series.label}
)}
);
};
const FullFeaturedChart = () => {
const bus = createPluginBus();
return (
);
};
```
### Responsive Chart
```tsx
const ResponsiveChart = () => {
return (
);
};
```
### External Integration
```tsx
const Dashboard = () => {
const bus = createPluginBus();
const handleSeriesToggle = (seriesLabel: string) => {
bus.setData("focusSeries", {
sourceId: "external-control",
targets: [{ label: seriesLabel }],
});
};
return (
handleSeriesToggle("Series 1")}>Focus Series 1
handleSeriesToggle("Series 2")}>Focus Series 2
);
};
```
## 🎮 Interactive Playground
This library includes a comprehensive playground application that demonstrates all features and provides interactive examples. The playground showcases:
- **Basic Charts**: Simple line charts with different configurations
- **Plugin Examples**: All built-in plugins working together
- **Legend Showcase**: Various legend patterns and interactions
- **Responsive Sizing**: Auto-resize and manual sizing examples
- **Custom Plugins**: Examples of creating your own plugins
- **External Integration**: Charts interacting with external components
### Running the Playground Locally
To explore the playground and see the library in action:
```bash
# Clone the repository
git clone https://github.com/dsnchz/solid-uplot.git
cd solid-uplot
# Install dependencies
npm install
# or
pnpm install
# or
yarn install
# or
bun install
# Start the playground development server
npm run start
# or
pnpm start
# or
yarn start
# or
bun start
```
The playground will be available at `http://localhost:3000` and includes:
- **Live code examples** with syntax highlighting
- **Interactive demos** you can modify in real-time
- **Performance comparisons** between different configurations
- **Best practices** and common patterns
- **Plugin development examples** with step-by-step guides
The playground source code also serves as a comprehensive reference for implementing various chart patterns and plugin combinations.
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Also check out the [Discord](https://discord.gg/6wkpXQCNn6) community.
## 📄 License
MIT