@dschz/solid-uplot

中文文档
0.5.2发布于 2026/02/04MITTypeScriptES Module零依赖近 30 天下载 3861

用于 uPlot 的 SolidJS 包装器 — 超快, 极小的时间序列和图表库

中文使用文档
文档目录27 节
  1. * 特性
  2. * 安装
  3. 现场直播
  4. 运行游戏场
  5. QQ 软件包结构
  6. @dschz/solid-uplot
  7. @dschz/solid-uplot/plugins
  8. @dschz/solid-uplot/utils
  9. QQ 快速启动
  10. 响应大小
  11. 增强插件系统
  12. 插件总线架构
  13. 内置插件
  14. 插件总线类型安全
  15. 创建自定义插件
  16. 外部构成部分
  17. API 参考
  18. SolidUplot 组件
  19. 插件总线
  20. 内建插件选项
  21. 实例
  22. 基本图表
  23. 带有全部插件的图表
  24. 响应图表
  25. 外部一体化
  26. 捐款
  27. 许可证

@dschz/solid-uplot banner

@dschz/ 固态升起

License uPlot npm Bundle Size JSR CI Discord

固态JS包装器 uPlot 地图 ——用于时间序列数据的超快小脚印图库.

* 特性

  • uPlot周围的全反应固体JS包装器
  • 插件系统支持与插件间通信
  • 对图表生命周期的精细控制
  • 轻而易举
  • 框外的 QQ 类型脚本支持
  • QQ 用于工具提示、 传说、 光标跟踪和系列焦点的内置插件
  • * 以自动调整规模的能力响应规模支持

* 安装

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

现场直播

这艘反转船有一个 直播,操场 ——全面展示图书馆每个特色. 这是最快的方法 solid-uplot 并探索图表、插件、响应大小和外部集成等真实的、可行的实例.

运行游戏场

git clone https://github.com/dsnchz/solid-uplot.git
cd solid-uplot

# Install dependencies
bun install

# Start the playground
bun start

游乐场运行在 http://localhost:3000 并包括交互式演示:

  • 所有内置插件( 曲线、 工具提示、 传说、 焦点系列)
  • 响应和自动调整图型
  • 自定义插件开发
  • 通过插件总线进行外部组件集成

QQ 软件包结构

这个软件包为不同的功能提供了三个主要导出路径:

@dschz/solid-uplot

核心组件和插件系统 :

import { SolidUplot, createPluginBus } from "@dschz/solid-uplot";
import type {
  SolidUplotPluginBus,
  UplotPluginFactory,
  UplotPluginFactoryContext,
} from "@dschz/solid-uplot";

@dschz/solid-uplot/plugins

此导出路径提供了四个插件(其中三个可以被认为是原始的).

  • cursor: 传送光标位置数据
  • focusSeries: 传送在视觉上强调的系列
  • tooltip: 允许您在光标周围显示自定义 JSX 工具提示的插件
  • legend: 插件, 允许您在画布绘制区域上将自定义 JSX 组件作为您的传说 .
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

从 a 获取某些位点数据的便利工具函数 uPlot 实例(除 getColorString 翻译系列 stroke 或者说 fill 输入颜色值).

import {
  getSeriesData,
  getCursorData,
  getColorString,
  getNewCalendarDayIndices,
} from "@dschz/solid-uplot/utils";
import type { SeriesDatum, CursorData } from "@dschz/solid-uplot/utils";

QQ 快速启动

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) => (
  <div style={{ background: "white", padding: "8px", border: "1px solid #ccc" }}>
    <div>X: {props.cursor.xValue}</div>
    <For each={props.seriesData}>
      {(series) => {
        const value = props.u.data[series.seriesIdx]?.[props.cursor.idx];
        return (
          <div>
            {series.label}: {value}
          </div>
        );
      }}
    </For>
  </div>
);

// Create a legend component
const MyLegend = (props: LegendProps) => (
  <div style={{ background: "rgba(255,255,255,0.9)", padding: "8px" }}>
    <For each={props.seriesData}>
      {(series) => (
        <div style={{ display: "flex", "align-items": "center", gap: "4px" }}>
          <div
            style={{
              width: "12px",
              height: "12px",
              background: series.stroke,
            }}
          />
          <span>{series.label}</span>
        </div>
      )}
    </For>
  </div>
);

const MyChart = () => {
  const bus = createPluginBus<CursorPluginMessageBus>();

  return (
    <SolidUplot
      data={[
        [0, 1, 2, 3], // x values
        [10, 20, 30, 40], // y values for series 1
        [15, 25, 35, 45], // y values for series 2
      ]}
      width={600}
      height={400}
      series={[
        {},
        { label: "Series 1", stroke: "#1f77b4" },
        { label: "Series 2", stroke: "#ff7f0e" },
      ]}
      plugins={[
        cursor(),
        tooltip(MyTooltip),
        legend(MyLegend, { placement: "top-right", pxOffset: 12 }),
      ]}
      pluginBus={bus}
    />
  );
};

响应大小

对于自动适应容器大小变化的响应性图表,使用 autoResize 道具 :

<div style={{ width: "100%", height: "400px" }}>
  <SolidUplot
    autoResize={true}
    data={data}
    series={series}
    // Chart will automatically resize to fill the container
  />
</div>

对于更先进的响应模式,您可以将这个库与 @dschz/ 固态自动喷雾器数字 :

npm install @dschz/solid-auto-sizer
pnpm install @dschz/solid-auto-sizer
yarn install @dschz/solid-auto-sizer
bun install @dschz/solid-auto-sizer
import { AutoSizer } from "@dschz/solid-auto-sizer";

<AutoSizer>
  {({ width, height }) => <SolidUplot width={width} height={height} data={data} />}
</AutoSizer>;

或者,你可以使用 createElementSize 从 @solid-primitives/resize-observer 基于信号的方法:

npm install @solid-primitives/resize-observer
import { createElementSize } from "@solid-primitives/resize-observer";

const ResponsiveChart = () => {
  let container!: HTMLDivElement;
  const size = createElementSize(() => container);

  return (
    <div style={{ width: "100%", height: "400px" }}>
      <div ref={container} style={{ width: "100%", height: "100%" }}>
        <SolidUplot data={data} width={size.width ?? 0} height={size.height ?? 0} series={series} />
      </div>
    </div>
  );
};

增强插件系统

其基本特征是: SolidUplot 是其精细的插件系统,通过反应性消息总线,能够扩展功能并进行插件间通信.

插件总线架构

插件总线系统使插件能够通过反应存储器相互和外部组件通信. 这一架构提供:

  • 安全型通信: 所有插件信件已全部输入
  • 反应更新: 插件状态的变化自动触发更新
  • 脱钩组件: 插件可以在没有直接依赖的情况下相互作用
  • 广泛: 方便添加与现有插件相融合的新插件

内置插件

光标插件

跟踪光标位置和跨图表的交互状态:

import { cursor } from "@dschz/solid-uplot/plugins";
import type { CursorPluginMessageBus } from "@dschz/solid-uplot/plugins";

const cursorPlugin = cursor();

光标插件提供光标位置数据,其他插件可以通过总线消耗.

焦点系列插件

基于光标相近性的突出显示系列 :

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

工具提示插件

装有自动定位和外溢处理的自定义工具提示:

import { tooltip } from "@dschz/solid-uplot/plugins";
import type { TooltipProps } from "@dschz/solid-uplot/plugins";

const MyTooltip: Component<TooltipProps> = (props) => {
  return (
    <div
      style={{
        background: "white",
        border: "1px solid #ccc",
        padding: "8px",
        "border-radius": "4px",
        "box-shadow": "0 2px 4px rgba(0,0,0,0.1)",
      }}
    >
      <div style={{ "font-weight": "bold", "margin-bottom": "8px" }}>X: {props.cursor.xValue}</div>
      <For each={props.seriesData}>
        {(series) => {
          const value = () => props.u.data[series.seriesIdx]?.[props.cursor.idx];
          return (
            <Show when={series.visible}>
              <div style={{ display: "flex", "align-items": "center", "margin-bottom": "4px" }}>
                <div
                  style={{
                    width: "10px",
                    height: "10px",
                    "border-radius": "50%",
                    "background-color": series.stroke,
                    "margin-right": "6px",
                  }}
                />
                <span style={{ color: series.stroke }}>
                  {series.label}: {value()?.toFixed(2)}
                </span>
              </div>
            </Show>
          );
        }}
      </For>
    </div>
  );
};

const tooltipPlugin = tooltip(MyTooltip, {
  placement: "top-left", // "top-left" | "top-right" | "bottom-left" | "bottom-right"
  zIndex: 20,
});

图例插件

添加具有智能定位和交互特性的自定义的传说 :

import { legend } from "@dschz/solid-uplot/plugins";
import type { LegendProps } from "@dschz/solid-uplot/plugins";

const MyLegend: Component<LegendProps> = (props) => {
  // Access cursor data for interactive features
  const cursorVisible = () => props.bus.data.cursor?.state[props.u.root.id]?.visible;

  return (
    <div
      style={{
        background: "white",
        border: "1px solid #ddd",
        "border-radius": "4px",
        padding: "8px",
        "box-shadow": "0 2px 4px rgba(0,0,0,0.1)",
        // Dim when tooltip is active
        opacity: cursorVisible() ? 0.6 : 1,
        transition: "opacity 200ms",
      }}
    >
      <div style={{ "font-weight": "bold", "margin-bottom": "8px" }}>Legend</div>
      <For each={props.seriesData}>
        {(series) => (
          <Show when={series.visible}>
            <div
              style={{
                display: "flex",
                "align-items": "center",
                gap: "6px",
                "margin-bottom": "4px",
              }}
            >
              <div
                style={{
                  width: "12px",
                  height: "12px",
                  "background-color": series.stroke,
                  "border-radius": "2px",
                }}
              />
              <span style={{ "font-size": "14px" }}>{series.label}</span>
            </div>
          </Show>
        )}
      </For>
    </div>
  );
};

const legendPlugin = legend(MyLegend, {
  placement: "top-left", // "top-left" | "top-right"
  pxOffset: 8, // Distance from chart edges (default: 8)
  zIndex: 10,
});

图例插件特征 :

  • 简单定位: 只有左上或右上角避免轴冲突
  • 大小限制: 图例不能超过图表绘图区域维度
  • 布局不可知: 控制内部布局和样式
  • 非干涉: 设计与图表互动和谐工作
  • 插件总线集成: 获取光标和焦点数据进行智能互动
  • 自动清理: 适当的内存管理和DOM清理

插件总线类型安全

在使用多个插件时,通过正确打入插件总线确保类型安全:

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<CursorPluginMessageBus & FocusSeriesPluginMessageBus>();

const MyChart = () => {
  return (
    <SolidUplot
      data={data}
      pluginBus={bus}
      plugins={[cursor(), focusSeries(), tooltip(MyTooltip), legend(MyLegend)]}
    />
  );
};

创建自定义插件

插件系统可扩展。 编写用于公共消费的插件时,遵循此模式:

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<CursorPluginMessageBus & MyPluginMessageBus> => {
  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);
        },
      },
    };
  };
};

外部构成部分

插件总线可以在图表和外部组件之间实现强大的集成:

import { createPluginBus } from "@dschz/solid-uplot";
import type { FocusSeriesPluginMessageBus } from "@dschz/solid-uplot/plugins";

const bus = createPluginBus<FocusSeriesPluginMessageBus>();

// 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 <table>{/* Grid implementation */}</table>;
};

// Chart and grid interact through shared bus
const MyDashboard = () => {
  return (
    <div>
      <DataGrid bus={bus} />
      <SolidUplot data={data} pluginBus={bus} plugins={[focusSeries()]} />
    </div>
  );
};

API 参考

SolidUplot 组件

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<T extends VoidStruct = VoidStruct> = SolidUplotOptions<T> &
  SolidUplotEvents & {
    // Ref callback to access the chart container element
    ref?: Ref<HTMLDivElement>;

    // 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<JSX.CSSProperties, "position">;

    // 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<T extends VoidStruct = VoidStruct> = Omit<
  uPlot.Options,
  "plugins" | "width" | "height"
> & {
  // Chart dimensions
  width?: number; // default: 600
  height?: number; // default: 300

  // Plugin configuration
  plugins?: SolidUplotPlugin<T>[];
  pluginBus?: SolidUplotPluginBus<T>;
};

// Plugin type (can be standard uPlot plugin or factory function)
type SolidUplotPlugin<T extends VoidStruct = VoidStruct> = uPlot.Plugin | UplotPluginFactory<T>;

插件总线

// Plugin bus type (derived from createPluginBus return type)
type SolidUplotPluginBus<T extends VoidStruct = VoidStruct> = ReturnType<typeof createPluginBus<T>>;

// Create a plugin bus
const createPluginBus: <T extends VoidStruct = VoidStruct>(
  initialData?: T,
) => SolidUplotPluginBus<T>;

内建插件选项

// Cursor Plugin
const cursor = (): UplotPluginFactory<CursorPluginMessageBus>;

// Focus Series Plugin
const focusSeries = (options?: {
  pxThreshold?: number; // default: 15
}): UplotPluginFactory<CursorPluginMessageBus & FocusSeriesPluginMessageBus>;

// Tooltip Plugin
const tooltip = (
  Component: Component<TooltipProps>,
  options?: {
    placement?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
    id?: string;
    class?: string;
    style?: JSX.CSSProperties;
    zIndex?: number; // default: 20
  }
): UplotPluginFactory<CursorPluginMessageBus & FocusSeriesPluginMessageBus>;

// Legend Plugin
const legend = (
  Component: Component<LegendProps>,
  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<CursorPluginMessageBus & FocusSeriesPluginMessageBus>;

实例

基本图表

import { SolidUplot } from "@dschz/solid-uplot";

const BasicChart = () => {
  return (
    <SolidUplot
      data={[
        [0, 1, 2, 3],
        [10, 20, 30, 40],
        [15, 25, 35, 45],
      ]}
      width={600}
      height={400}
      scales={{
        x: { time: false },
      }}
      series={[
        {},
        { label: "Series 1", stroke: "#1f77b4" },
        { label: "Series 2", stroke: "#ff7f0e" },
      ]}
    />
  );
};

带有全部插件的图表

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<TooltipProps> = (props) => (
  <div style={{ background: "white", padding: "8px", border: "1px solid #ccc" }}>
    <div>Time: {new Date(props.cursor.xValue * 1000).toLocaleTimeString()}</div>
    <For each={props.seriesData}>
      {(series) => {
        const value = props.u.data[series.seriesIdx]?.[props.cursor.idx];
        return (
          <div style={{ color: series.stroke }}>
            {series.label}: {value?.toFixed(2)}
          </div>
        );
      }}
    </For>
  </div>
);

const MyLegend: Component<LegendProps> = (props) => {
  const cursorVisible = () => props.bus.data.cursor?.state[props.u.root.id]?.visible;

  return (
    <div
      style={{
        background: "white",
        border: "1px solid #ddd",
        padding: "8px",
        opacity: cursorVisible() ? 0.6 : 1,
        transition: "opacity 200ms",
      }}
    >
      <For each={props.seriesData}>
        {(series) => (
          <div style={{ display: "flex", "align-items": "center", gap: "6px" }}>
            <div
              style={{
                width: "12px",
                height: "12px",
                background: series.stroke,
              }}
            />
            <span>{series.label}</span>
          </div>
        )}
      </For>
    </div>
  );
};

const FullFeaturedChart = () => {
  const bus = createPluginBus<CursorPluginMessageBus & FocusSeriesPluginMessageBus>();

  return (
    <SolidUplot
      data={[
        [0, 1, 2, 3, 4, 5],
        [10, 20, 30, 40, 50, 60],
        [15, 25, 35, 45, 55, 65],
        [5, 15, 25, 35, 45, 55],
      ]}
      width={800}
      height={500}
      series={[
        {},
        { label: "Revenue", stroke: "#1f77b4" },
        { label: "Profit", stroke: "#ff7f0e" },
        { label: "Expenses", stroke: "#2ca02c" },
      ]}
      plugins={[
        cursor(),
        focusSeries({ pxThreshold: 20 }),
        tooltip(MyTooltip, { placement: "top-right" }),
        legend(MyLegend, { placement: "top-left", pxOffset: 12 }),
      ]}
      pluginBus={bus}
    />
  );
};

响应图表

const ResponsiveChart = () => {
  return (
    <div style={{ width: "100%", height: "400px", border: "1px solid #ccc" }}>
      <SolidUplot
        autoResize={true}
        data={data}
        series={series}
        plugins={[cursor(), tooltip(MyTooltip)]}
      />
    </div>
  );
};

外部一体化

const Dashboard = () => {
  const bus = createPluginBus<FocusSeriesPluginMessageBus>();

  const handleSeriesToggle = (seriesLabel: string) => {
    bus.setData("focusSeries", {
      sourceId: "external-control",
      targets: [{ label: seriesLabel }],
    });
  };

  return (
    <div>
      <div>
        <button onClick={() => handleSeriesToggle("Series 1")}>Focus Series 1</button>
        <button onClick={() => handleSeriesToggle("Series 2")}>Focus Series 2</button>
      </div>
      <SolidUplot data={data} plugins={[focusSeries()]} pluginBus={bus} />
    </div>
  );
};

捐款

欢迎捐款! 请随意提交拉力请求.

还有看 解析器 社区.

许可证

麻省理工学院

版本与发布记录

@dschz/solid-uplot 共发布 14 个版本,首次发布于 2025/05/28;过去 12 个月发布了 5 个版本。

版本发布日期距今
0.5.2latest2026/02/049 个月前
0.5.12026/02/049 个月前
0.5.02026/02/049 个月前
0.4.02025/11/2611 个月前
0.3.02025/11/2611 个月前
0.2.02025/06/171.4 年前

关于 @dschz/solid-uplot 的常见问题

@dschz/solid-uplot 是什么?

用于 uPlot 的 SolidJS 包装器 — 超快, 极小的时间序列和图表库

如何安装 @dschz/solid-uplot?

在项目目录运行 npm install @dschz/solid-uplot,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:solid-js(>=1.6.0)、uplot(>=1.6.32)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@dschz/solid-uplot 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dschz/solid-uplot 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@dschz/solid-uplot 可以商用吗?

@dschz/solid-uplot 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dschz/solid-uplot 的下载量有多少?

根据 npm 官方下载统计,@dschz/solid-uplot 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,861 次,日均约 129 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dschz/solid-uplot 还在维护吗?

最新版本 0.5.2 发布于 2026/02/04(9 个月前);至今共发布 14 个版本,其中过去 12 个月发布了 5 个;首次发布于 2025/05/28。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。