@dschz/solid-plotly
Version:
SolidJS wrapper for Plotly.js – reactive and performant charts powered by Plotly, built for Solid.
288 lines (284 loc) • 11.5 kB
TypeScript
import * as plotly_js from 'plotly.js';
import { FrameAnimationEvent, PlotMouseEvent, ClickAnnotationEvent, PlotHoverEvent, LegendClickEvent, PlotRelayoutEvent, PlotRestyleEvent, PlotSelectionEvent, SliderChangeEvent, SliderEndEvent, SliderStartEvent, SunburstClickEvent, PlotlyHTMLElement } from 'plotly.js';
import { JSX } from 'solid-js';
/**
* Plotly configuration object type.
*
* Defines options for plot behavior, appearance, and interaction settings.
* This is a partial type of Plotly.Config, allowing any subset of configuration options.
*
* @example
* ```tsx
* const config: PlotlyConfig = {
* displayModeBar: true,
* responsive: true,
* toImageButtonOptions: {
* format: 'png',
* filename: 'custom_image'
* }
* };
* ```
*/
type PlotlyConfig = Partial<Plotly.Config>;
/**
* Single data trace type for Plotly charts.
*
* Represents one data series/trace that can be plotted. Multiple PlotlyData objects
* make up the data array passed to a chart.
*
* @example
* ```tsx
* const trace: PlotlyData = {
* x: [1, 2, 3, 4],
* y: [10, 11, 12, 13],
* type: 'scatter',
* mode: 'lines+markers',
* name: 'Sample Data'
* };
* ```
*/
type PlotlyData = Plotly.Data;
/**
* Animation frame type for animated Plotly charts.
*
* Used to define individual frames in animated visualizations, allowing for
* smooth transitions between different states of data.
*
* @example
* ```tsx
* const frame: PlotlyFrame = {
* name: 'frame1',
* data: [{ x: [1, 2], y: [1, 4] }],
* layout: { title: 'Frame 1' }
* };
* ```
*/
type PlotlyFrame = Plotly.Frame;
/**
* Plotly layout configuration type.
*
* Defines the overall appearance and structure of the plot including axes,
* titles, margins, colors, and other visual elements. This is a partial type
* allowing any subset of layout options.
*
* @example
* ```tsx
* const layout: PlotlyLayout = {
* title: 'My Chart Title',
* xaxis: { title: 'X Axis' },
* yaxis: { title: 'Y Axis' },
* margin: { t: 50, l: 50, r: 50, b: 50 }
* };
* ```
*/
type PlotlyLayout = Partial<Plotly.Layout>;
type VoidHandler = () => void;
/**
* Complete interface for all Plotly event handlers supported by the component.
*
* Provides type-safe event handling for all Plotly.js events including mouse interactions,
* selections, layout changes, UI element interactions, and plot lifecycle events.
* All event handlers are optional.
*
* @example
* ```tsx
* const eventHandlers: Partial<PlotComponentEventHandlers> = {
* onClick: (event) => console.log('Point clicked:', event.points[0]),
* onHover: (event) => console.log('Hovering over:', event.points[0]),
* onRelayout: (event) => console.log('Layout changed:', event),
* onSelected: (event) => console.log('Points selected:', event.points)
* };
* ```
*
* @remarks
* Event handlers are organized into several categories:
* - **Mouse Events**: onClick, onDoubleClick, onHover, onUnhover
* - **Selection Events**: onSelected, onSelecting, onDeselect
* - **Layout Events**: onRelayout, onRelayouting, onRestyle
* - **Legend Events**: onLegendClick, onLegendDoubleClick
* - **UI Events**: onClickAnnotation, onSliderChange, onSliderStart, onSliderEnd
* - **Lifecycle Events**: onAfterPlot, onBeforePlot, onRedraw, onAutoSize
* - **Animation Events**: onAnimated, onAnimatingFrame, onTransitioning
*/
type PlotComponentEventHandlers = {
/** Fired when an animation frame is being processed */
onAnimatingFrame?: (event: FrameAnimationEvent) => void;
/** Fired before plot rendering begins - return false to cancel */
onBeforePlot?: (event: Event) => boolean;
/** Fired when a data point is clicked */
onClick?: (event: PlotMouseEvent) => void;
/** Fired when an annotation is clicked */
onClickAnnotation?: (event: ClickAnnotationEvent) => void;
/** Fired when hovering over a data point */
onHover?: (event: PlotHoverEvent) => void;
/** Fired when a legend item is clicked - return false to prevent default behavior */
onLegendClick?: (event: LegendClickEvent) => boolean;
/** Fired when a legend item is double-clicked - return false to prevent default behavior */
onLegendDoubleClick?: (event: LegendClickEvent) => boolean;
/** Fired when the plot layout is changed (zoom, pan, resize) */
onRelayout?: (event: PlotRelayoutEvent) => void;
/** Fired continuously while the layout is being changed */
onRelayouting?: (event: PlotRelayoutEvent) => void;
/** Fired when plot styling properties are changed */
onRestyle?: (data: PlotRestyleEvent) => void;
/** Fired when data points are selected */
onSelected?: (event: PlotSelectionEvent) => void;
/** Fired continuously while selecting data points */
onSelecting?: (event: PlotSelectionEvent) => void;
/** Fired when a slider value is changed */
onSliderChange?: (event: SliderChangeEvent) => void;
/** Fired when slider interaction ends */
onSliderEnd?: (event: SliderEndEvent) => void;
/** Fired when slider interaction starts */
onSliderStart?: (event: SliderStartEvent) => void;
/** Fired when a sunburst chart segment is clicked */
onSunburstClick?: (event: SunburstClickEvent) => void;
/** Fired when mouse leaves a data point */
onUnhover?: (event: PlotMouseEvent) => void;
/** Fired after export operation completes */
onAfterExport?: VoidHandler;
/** Fired after plot rendering completes */
onAfterPlot?: VoidHandler;
/** Fired after animation completes */
onAnimated?: VoidHandler;
/** Fired when animation is interrupted */
onAnimationInterrupted?: VoidHandler;
/** Fired when plot auto-resizes */
onAutoSize?: VoidHandler;
/** Fired before export operation begins */
onBeforeExport?: VoidHandler;
/** Fired when selection is cleared */
onDeselect?: VoidHandler;
/** Fired when plot is double-clicked */
onDoubleClick?: VoidHandler;
/** Fired for framework-specific events */
onFramework?: VoidHandler;
/** Fired when plot is redrawn */
onRedraw?: VoidHandler;
/** Fired during plot transitions */
onTransitioning?: VoidHandler;
/** Fired when transition is interrupted */
onTransitionInterrupted?: VoidHandler;
/** Generic event handler for any plot event */
onEvent?: (data: any) => void;
};
/**
* Complete plot figure data structure containing all plot information.
*
* Represents the full state of a Plotly chart including data traces, layout configuration,
* and animation frames. This type is used in lifecycle callbacks to provide access
* to the complete plot state.
*
* @example
* ```tsx
* const onInitialized = (figure: PlotlyFigure, element: PlotlyHTMLElement) => {
* console.log('Plot initialized with', figure.data.length, 'traces');
* console.log('Title:', figure.layout.title);
* if (figure.frames) {
* console.log('Animation frames:', figure.frames.length);
* }
* };
* ```
*/
type PlotlyFigure = {
/** Array of data traces in the plot */
readonly data: Plotly.Data[];
/** Layout configuration of the plot */
readonly layout: Partial<Plotly.Layout>;
/** Animation frames if present, null otherwise */
readonly frames: Plotly.Frame[] | null;
};
type UpdateFigureCallback = (figure: PlotlyFigure, el: PlotlyHTMLElement) => void;
/**
* Props interface for the Plot component created by createPlotComponent.
*
* Combines all Plotly event handlers with component-specific props for data visualization.
* All props except `data` are optional, allowing for flexible usage patterns.
*
* @example
* ```tsx
* const Plot = createPlotComponent(Plotly);
*
* <Plot
* data={[{ x: [1, 2, 3], y: [1, 4, 2], type: 'scatter' }]}
* layout={{ title: 'My Chart' }}
* onClick={(event) => console.log('Clicked:', event.points)}
* useResize={true}
* />
* ```
*/
type PlotProps = PlotComponentEventHandlers & {
/** Unique identifier for the plot container element @default "solid-plotly" */
readonly id?: string;
/** CSS class name(s) to apply to the plot container @default undefined */
readonly class?: string;
/** Inline CSS styles for the plot container @default { position: "relative", display: "inline-block" } */
readonly style?: JSX.CSSProperties;
/** Plotly configuration options for plot behavior and appearance @default {} */
readonly config?: PlotlyConfig;
/** Array of data traces to be plotted (required) @default [] */
readonly data: PlotlyData[];
/** Animation frames for animated plots @default [] */
readonly frames?: PlotlyFrame[];
/** Layout configuration for axes, title, margins, etc. @default {} */
readonly layout?: PlotlyLayout;
/** Callback fired when the plot is first initialized @default undefined */
readonly onInitialized?: UpdateFigureCallback;
/** Callback fired when the plot is purged/destroyed @default undefined */
readonly onPurge?: UpdateFigureCallback;
/** Callback fired when the plot data/layout is updated @default undefined */
readonly onUpdate?: UpdateFigureCallback;
/** Callback fired when the plot is resized (only when useResize is true) @default undefined */
readonly onResize?: () => void;
/** Callback fired when an error occurs during plot operations @default undefined */
readonly onError?: (e: Error) => void;
/** Ref callback to access the underlying HTML div element @default undefined */
readonly ref?: (el: HTMLDivElement) => void;
/** Enable automatic plot resizing when container size changes @default true */
readonly useResize?: boolean;
};
/**
* Subset of Plotly.js module interface required by the component.
*
* This type ensures that only the necessary Plotly.js functions are used,
* allowing for tree-shaking and compatibility with different Plotly.js bundles.
*
* @example
* ```tsx
* import Plotly from 'plotly.js-dist-min';
* import { createPlotComponent } from '@dschz/solid-plotly';
*
* const Plot = createPlotComponent(Plotly);
* ```
*/
type PlotlyModule = Pick<typeof plotly_js, "newPlot" | "react" | "purge" | "Plots">;
/**
* Factory function that creates a Plot component bound to a specific Plotly.js module.
*
* This approach allows users to choose their preferred Plotly.js bundle (full, basic, minimal)
* while keeping the library agnostic to specific Plotly.js dependencies.
*
* @param Plotly - Plotly.js module containing required methods (newPlot, react, purge, Plots)
* @returns A SolidJS component that renders interactive Plotly charts
*
* @example
* ```tsx
* import Plotly from 'plotly.js-dist-min';
* import { createPlotComponent } from '@dschz/solid-plotly';
*
* const Plot = createPlotComponent(Plotly);
*
* function MyChart() {
* const data = [{ x: [1, 2, 3], y: [1, 4, 2], type: 'scatter' }];
* return <Plot data={data} useResize={true} />;
* }
* ```
*
* @remarks
* - The returned component uses SolidJS fine-grained reactivity for optimal performance
* - Automatically handles plot initialization, updates, and cleanup
* - Supports all Plotly.js event handlers through props
* - Includes built-in resize handling when useResize is enabled
*/
declare const createPlotComponent: (Plotly: PlotlyModule) => (props: PlotProps) => JSX.Element;
export { type PlotComponentEventHandlers, type PlotProps, type PlotlyConfig, type PlotlyData, type PlotlyFigure, type PlotlyFrame, type PlotlyLayout, type PlotlyModule, createPlotComponent };