UNPKG

@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
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 };