关于 lightweight-charts
lightweight-charts 是一项帮助开发者使用 lightweight-charts API 的技能,适用于下游 npm 项目和上游源码仓库。它优先依据本地类型定义核对版本与 API,并提供 v5 用法及旧版迁移指导。
主要功能
- 01根据本地类型定义核实 API
- 02区分 npm 使用项目与源码仓库
- 03说明 v5 图表、序列和面板用法
- 04排查时间、交互和实时更新问题
- 05对照 v4 与 v5 的 API 变更
适用场景
- 01根据已安装版本编写图表代码
- 02排查时间戳单位或数据排序问题
- 03将旧版序列与标记代码迁移至 v5
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tradingview/ lightweight-charts --skill lightweight-charts安装后在 Claude Code 中输入/lightweight-charts确认已加载。
详细介绍
Lightweight Charts 技能
无论项目是下游 npm 消费者应用,还是上游 lightweight-charts 源码检出,使用方式都相同。请先判断当前属于哪种情况(见下文),并根据本地可用的类型定义解析所有 API 名称。
源码查找顺序
不要假设当前位于上游源码仓库中。
- 在消费者应用中,先检查已安装的包:
node_modules/lightweight-charts/package.json,确认实际版本。node_modules/lightweight-charts/dist/typings.d.ts,查看 API 范围。
- 在上游仓库中,先检查
dist/typings.d.ts,再检查src/(如果生成的输出不可用)。 - 官方文档和示例可作为辅助依据,但如果与本地类型定义不一致,以本地类型定义为准。
回答前请验证(复制粘贴):
node -p "require('./node_modules/lightweight-charts/package.json').version"
rg -n "createSeriesMarkers|addSeries|IPrimitivePaneRenderer|createImageWatermark|createOptionsChart" node_modules/lightweight-charts/dist/typings.d.ts
# upstream checkout instead of a consumer app:
rg -n "createSeriesMarkers|IPrimitivePaneRenderer|createImageWatermark|createOptionsChart" dist/typings.d.ts src
如果相关文件不可用,请说明无法验证的内容。不要臆造选项名称、方法、导出项或封装行为。
如果用户的代码使用 from lightweight_charts import ...(下划线)导入,使用 pandas/asyncio,或提到 Python 窗口封装,他们很可能使用的是第三方 Python 封装,而不是 TypeScript 包。给出 lightweight-charts v5 JavaScript 核心库的建议前,请先明确说明这一点。
心智模型
八个层次,按依赖顺序排列。大多数错误都源于混淆这些层次:
- 图表 —
createChart(container, options)返回一个IChartApi。每个容器元素对应一个图表。 - 序列 — 通过
chart.addSeries(SeriesType, options, paneIndex?)添加。每次调用都会返回一个ISeriesApi。v5 要求显式导入序列类型。 - 刻度 —
chart.timeScale()(ITimeScaleApi)、chart.priceScale(id)(IPriceScaleApi)。控制范围、刻度线、自动缩放和可见性。 - 数据模型 —
{ time, … }数据点数组。Time = UTCTimestamp | BusinessDay | string。UTCTimestamp的单位是秒,不是毫秒。每个序列中的时间必须唯一且按升序排列。 - 交互 —
chart.subscribeCrosshairMove、chart.subscribeClick、timeScale.subscribeVisibleLogicalRangeChange等。 - 布局 —
chart.panes()、chart.addPane()。使用超出范围的paneIndex添加序列时,会自动创建窗格。 - 扩展 — 窗格图元、序列图元、自定义序列、水印、自定义渲染器(通过
fancy-canvas使用 canvas)。 - 封装 — React/Vue/Web Components/iOS/Android。生命周期由封装负责;核心库与框架无关。
v5 基础
以下约定能避免照搬旧代码片段时常见的问题:
import { createChart, CandlestickSeries, LineSeries } from 'lightweight-charts';
const chart = createChart(container, { /* ChartOptions */ });
const candles = chart.addSeries(CandlestickSeries, { /* options */ });
candles.setData([
{ time: 1700000000, open: 1, high: 2, low: 0.5, close: 1.5 },
]);
与旧代码片段相比,v5 的主要变化:
chart.addSeries(SeriesType, options, paneIndex?)取代addLineSeries/addCandlestickSeries/ …createSeriesMarkers(series, markers)取代series.setMarkers(...)。返回的图元提供.setMarkers(...)/.markers()。createTextWatermark(pane, options)和createImageWatermark(pane, imageUrl, options)取代watermark图表选项。- 序列类型会被 tree-shaking,因此 ESM 必须显式导入这些类型。
如果代码片段调用 addLineSeries 或 series.setMarkers,那么它使用的是 v4 或更早版本。转发前请确认用户使用的版本。
如果任务针对 v5,请直接展示 v5 API,不要混用 v4 语法来含糊其辞。
分类处理(问题 → API → 避免事项)
| 用户询问 | 首先检查 | 用以下内容作答 | 避免使用 |
|---|---|---|---|
| 创建 v5 系列 | 包版本 + 类型定义 | chart.addSeries(SeriesType, options) | addLineSeries / addCandlestickSeries |
| 标记 | 是否导出 createSeriesMarkers | 标记图元 + 必需的 color | series.setMarkers |
| 时区 | 格式化需求与数据语义 | 在格式化器中使用 Intl.DateTimeFormat | 虚构的 timeScale.timezone |
| 实时更新 | 更新最后一根柱还是完整替换 | series.update(point) | 每次跳动都调用 setData |
| 窗格 | paneIndex + chart.panes() | v5 窗格 API、pane.setHeight | 私有组件 / DOM 技巧 |
| 单柱颜色 | 数据点颜色字段 | 数据点上的 color/borderColor/wickColor | 用额外系列 / 标记来重新着色 |
| 插件 | 图元还是自定义系列 | 脚手架 / 示例 + 公开的坐标 API | 臆造的渲染器名称 |
v4 → v5 替换对照表
过时的复制粘贴代码片段是最常见的问题。请直接按以下内容替换:
| 旧版或错误用法 | v5 替代方案 |
|---|---|
chart.addLineSeries(options) | chart.addSeries(LineSeries, options) |
chart.addCandlestickSeries(options) | chart.addSeries(CandlestickSeries, options) |
series.setMarkers(markers) | createSeriesMarkers(series, markers) |
chart 的 watermark 选项 | createTextWatermark(chart.panes()[0], options) |
createImageWatermark(pane, options) | createImageWatermark(pane, imageUrl, options) |
IPanePrimitivePaneRenderer | IPrimitivePaneRenderer |
timeScale: { timezone } | 使用 Intl.DateTimeFormat 的标签格式化器 |
time: Date.now()(毫秒) | 对于 UTCTimestamp,使用 time: Math.floor(Date.now() / 1000) |
路由图(问题 → 查阅位置)
优先查看本地类型定义。以下仓库路径仅存在于上游 lightweight-charts 检出目录中;在使用者的应用中,应将其对应到已安装的包类型定义或官方文档。
| 任务 | 权威来源 |
|---|---|
| 首个图表 / 序列 | website/docs/intro.mdx、website/tutorials/customization/ |
| 时间 / 范围行为 | website/docs/time-scale.md、website/docs/time-zones.md |
| 实时数据 / 历史数据 | website/tutorials/demos/realtime-updates.{mdx,js}、website/tutorials/demos/infinite-history.{mdx,js} |
| 空白区域 / 间隙 | website/tutorials/demos/whitespace.{mdx,js} |
| 价格格式 / 区域设置 | website/tutorials/customization/price-format.mdx、website/tutorials/demos/custom-locale.{mdx,js} |
| 双刻度 / 反转 | website/tutorials/how_to/two-price-scales.{mdx,js}、website/tutorials/how_to/inverted-price-scale.{mdx,js} |
| 窗格 / 价格 + 成交量 | website/docs/panes.md、website/tutorials/how_to/panes.{mdx,js}、website/tutorials/how_to/price-and-volume.{mdx,js} |
| 标记 / 工具提示 / 图例 | website/tutorials/how_to/series-markers.{mdx,js}、website/tutorials/how_to/tooltips.mdx、website/tutorials/how_to/legends.mdx |
| 十字光标(程序化) | website/tutorials/how_to/set-crosshair-position*.js |
| 水印 | website/tutorials/how_to/watermark.mdx |
| 插件 / 自定义序列 / 基元 | website/docs/plugins/、plugin-examples/src/plugins/ |
| 坐标转换 / 命中测试 | 查看 dist/typings.d.ts 中的 subscribeClick、coordinateToPrice、timeScale().coordinateToLogical |
| 非时间水平刻度 / 期权图表 | 查看 dist/typings.d.ts 中的 createOptionsChart、createChartEx、IHorzScaleBehavior |
| 像素级精准渲染 | website/docs/plugins/pixel-perfect-rendering/ |
| React / Vue / Web Components | website/tutorials/react/、website/tutorials/vuejs/、website/tutorials/webcomponents/ |
| SSR / 脚本加载 / 打包工具 | 已安装包的 dist/ 文件、包的 exports,以及框架中关于仅客户端组件的文档 |
| iOS / Android 封装 | website/docs/ios.md、website/docs/android.md |
| 版本迁移 | website/docs/migrations/from-v2-to-v3.md、from-v3-to-v4.md、from-v4-to-v5.md |
如果用户的项目中不存在这些仓库路径,不要为了回答常见用法问题而让他们创建或克隆源码树。请使用 node_modules/lightweight-charts/dist/typings.d.ts 和简洁的 v5 示例。
易踩的坑(断言,而非类别)
时间
UTCTimestamp的单位是秒。 使用Math.floor(Date.now() / 1000),绝不要使用Date.now()。- 没有内置的
timeScale.timezone选项。 如需仅转换显示时区,请使用timeScale.tickMarkFormatter设置坐标轴标签,并使用localization.timeFormatter(或自定义的工具提示格式化函数)设置十字光标/悬停标签。使用Intl.DateTimeFormat(..., { timeZone })、Luxon 或 date-fns-tz,以支持安全处理夏令时的 IANA 时区格式化。 - 预先平移时间戳会改变图表语义。 这样可以让刻度与选定时区对齐,但也会改变柱形在 UTC 时间轴上的位置。除非用户明确需要平移数据,否则应优先使用格式化函数来显示。
- 系列数据必须严格按
time升序排列,且值必须唯一。 重复项会被静默替换;顺序错误的数据点会被丢弃或引发错误。 - 每个系列只能使用一种时间格式。 可以使用
BusinessDay('YYYY-MM-DD'字符串或{ year, month, day })或UTCTimestamp,但不要在同一系列中混用。 - 无值数据点只包含
time(不包含value/open/……)。可用它们创建间隔或对齐叠加层;不要将值设为null。 setData会替换数据集,并且可能重置可见范围。update(point)会在time > last时追加,在time === last时替换。update(point, true)可更新已有的历史数据点,但速度较慢,且不会插入缺失的旧数据点。要在前面添加较早的历史数据,请构建新数组并再次调用setData——没有前置插入方法;请保存并恢复可见逻辑范围,避免图表突然跳动。timeScale.setVisibleLogicalRange使用逻辑范围(柱形索引),而非基于时间的范围。 设置时间边界请使用setVisibleRange,重置则使用fitContent()。
刻度和窗格
- **要显示两个价格刻度,**既需要通过
priceScaleId: 'right'/'left'为系列指定价格刻度,也需要显示左侧刻度。使用chart.applyOptions({ leftPriceScale: { visible: true }, rightPriceScale: { visible: true } })或chart.priceScale('left').applyOptions({ visible: true })。 - 叠加系列(
priceScaleId: ''或任何自定义 ID)默认使用自动缩放且隐藏的刻度。如需显示坐标轴标签,请显式设为可见。 autoscaleInfoProvider会在每次布局时运行。 请保持轻量;不要在每次调用时分配内存。- 如果
paneIndex等于当前窗格数,addSeries(_, _, paneIndex)会创建窗格。 窗格顺序由创建顺序决定;可通过chart.panes()[i].setHeight(px)控制其大小。 - 如果窗格可能移动,请保留窗格引用。
const mainPane = chart.panes()[0]始终指向同一个IPaneApi;在swapPanes或移动后,mainPane.paneIndex()会返回其当前索引。 - 使用公开的时间刻度事件同步独立图表。 使用
subscribeVisibleLogicalRangeChange和setVisibleLogicalRange;避免使用_private__chartWidget、paneWidgets或依赖 DOM 偏移的变通方法。 - 可以读取价格刻度宽度,但无法直接设置。 使用
series.priceScale().width()或chart.priceScale(id).width()测量宽度,以便对齐相邻容器。
标记和交互
- v5 中的标记是一种图元。
const m = createSeriesMarkers(series, [...]); m.setMarkers([...])。v5 的ISeriesApi上不存在series.setMarkers。 - 标记的
time必须与该系列中某个现有数据点的time相同。 未对齐的标记会被静默丢弃。 subscribeCrosshairMove在数据范围之外触发时,param.time === undefined。读取前务必检查是否为null或undefined。- 在柱形之间或第一个柱形之前,
param.seriesData.get(series)会返回undefined。 - 点击/十字光标坐标需要通过 API 转换。 使用
series.coordinateToPrice(y)/series.priceToCoordinate(price)和chart.timeScale().coordinateToLogical(x)/logicalToCoordinate(logical)/timeToCoordinate(time);不要根据画布的 DOM 几何信息推断价格或时间。
插件和自定义渲染
- 从脚手架/示例开始编写插件。 在从头编写基础实现之前,优先使用
npm create lwc-plugin@latest和plugin-examples/。 - 交互式绘图工具需要两个部分: 用于渲染的基础实现/自定义序列,以及将坐标转换为公共 API 所用坐标的图表交互处理器(
subscribeClick、subscribeCrosshairMove、拖动状态)。 - **
CanvasRenderingTarget2D从fancy-canvas导入,**而不是从lightweight-charts导入。 - 像素对齐的描边使用
target.useBitmapCoordinateSpace(scope => …);CSS 像素逻辑使用target.useMediaCoordinateSpace(scope => …)。混用会导致 HiDPI 显示器上出现模糊或亚像素抖动。 IPanePrimitive视图会在整个窗格内渲染;ISeriesPrimitive视图会被限制在序列范围内。 选择合适的基类。- 渲染器接口是
IPrimitivePaneRenderer,不是IPanePrimitivePaneRenderer。 视图是IPanePrimitivePaneView,其renderer()返回IPrimitivePaneRenderer | null——这些名称有意采用不对称命名。没有IPanePrimitivePaneRenderer导出;不确定时,请在dist/typings.d.ts中 grep。 ICustomSeriesPaneView比基础实现更重。 仅在需要真正的序列 API(数据、刻度、自动缩放)时使用。装饰用途请使用基础实现。
封装层(React/Vue 等)
- **只在
useEffect/onMounted中创建一次图表,**并在清理时调用chart.remove()销毁图表。每次渲染都重新创建会导致 DOM 重复并泄漏监听器。 - **v5 中可以自动调整大小,**前提是
ResizeObserver可用且设置了autoSize: true。如需手动控制,请对容器订阅ResizeObserver,并调用chart.resize(width, height)(或applyOptions({ width, height }))。 - 不要在每次渲染时都根据 props 调用
setData。 增量更新请使用series.update(...);只有数据集确实被替换时才调用setData。 applyOptions中的undefined表示“未指定”,而不是“重置”。{ priceFormatter: custom ? fmt : undefined }会保留当前格式化器。要清除localization格式化器或autoscaleInfoProvider,请传入null。其他选项没有重置值:请显式传入默认值。- Next.js/SSR 必须仅在客户端运行。 将图表代码放入
'use client'组件中,在useEffect中创建图表;必要时,从服务器渲染的页面通过next/dynamic(..., { ssr: false })导入该组件。 - 纯 HTML 不会解析 npm 包。 独立的
.js构建会公开window.LightweightCharts;浏览器中的 ESM 必须导入实际的.mjsURL 或使用导入映射。只有在打包器/运行时解析包名时,import { createChart } from 'lightweight-charts'才有效。
标准方案
实时更新
import { createChart, CandlestickSeries } from 'lightweight-charts';
const chart = createChart(container, {});
const series = chart.addSeries(CandlestickSeries, {});
series.setData(initialBars); // full history once
ws.onmessage = ev => {
const bar = JSON.parse(ev.data); // { time, open, high, low, close }
series.update(bar); // appends if time > last; replaces if time === last
};
update() 只处理最新柱。要在中间插入或添加到开头,请重建数组并调用 setData。
两个价格刻度(左侧 + 右侧)
const right = chart.addSeries(LineSeries, { priceScaleId: 'right' });
const left = chart.addSeries(LineSeries, { priceScaleId: 'left' });
chart.applyOptions({
leftPriceScale: { visible: true },
rightPriceScale: { visible: true },
});
在单独的窗格中显示成交量
const price = chart.addSeries(CandlestickSeries, {}, 0);
const volume = chart.addSeries(
HistogramSeries,
{ priceFormat: { type: 'volume' } },
1,
);
chart.panes()[1].setHeight(120);
按柱/按点设置颜色
将颜色设置在数据点上,而不是通过单独的 API 为单个柱设置颜色:
// Candlesticks: per-point color / borderColor / wickColor override series defaults
candles.setData([
{ time: 1700000000, open: 1, high: 2, low: 0.5, close: 1.5,
color: '#26a69a', borderColor: '#26a69a', wickColor: '#26a69a' },
{ time: 1700003600, open: 1.5, high: 1.8, low: 1.1, close: 1.2,
color: '#ef5350', borderColor: '#ef5350', wickColor: '#ef5350' },
]);
// Histogram (e.g. up/down volume): per-point color
volume.setData([
{ time: 1700000000, value: 100, color: 'rgba(38,166,154,0.5)' },
{ time: 1700003600, value: 80, color: 'rgba(239,83,80,0.5)' },
]);
Line/Area 的点也支持按点设置 color。省略点颜色时,会回退到序列选项。不要创建额外序列,也不要使用标记为柱重新着色。
序列标记
import { createSeriesMarkers } from 'lightweight-charts';
const markers = createSeriesMarkers(candles, [
{ time: 1700000000, position: 'aboveBar', color: '#e53935', shape: 'arrowDown', text: 'Sell' },
]);
markers.setMarkers([
{ time: 1700003600, position: 'belowBar', color: '#43a047', shape: 'arrowUp', text: 'Buy' },
]);
每个标记都必须指定 color(position、shape、time 也同样必需);text、size、id、price 是可选的。不要将标记对象放入 setData() 数据点中。v5 中不要调用 series.setMarkers(...)。
时区显示
const zone = 'America/New_York';
const formatTime = (timestamp: number) =>
new Intl.DateTimeFormat('en-US', {
timeZone: zone,
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).format(new Date(timestamp * 1000));
chart.applyOptions({
timeScale: {
timeVisible: true,
secondsVisible: true,
tickMarkFormatter: (time) =>
typeof time === 'number' ? formatTime(time) : String(time),
},
localization: {
timeFormatter: (time) =>
typeof time === 'number' ? formatTime(time) : String(time),
},
});
不要臆造 timeScale: { timezone: 'America/New_York' }。如果用户需要按本地时区生成交易时段边界,请说明单独调整源时间戳与显示格式之间的取舍。
文本水印
import { createTextWatermark } from 'lightweight-charts';
createTextWatermark(chart.panes()[0], {
horzAlign: 'center',
vertAlign: 'center',
lines: [{ text: 'DEMO', color: 'rgba(0, 0, 0, 0.25)', fontSize: 48 }],
});
旧的 watermark 图表选项不是 v5 API。
空白间隙
line.setData([
{ time: '2024-01-01', value: 10 },
{ time: '2024-01-02' }, // whitespace point: time only
{ time: '2024-01-03', value: 12 },
]);
不要使用 value: null、undefined 或 NaN 创建间隙。
同步独立图表或窗格
let syncing = false;
priceChart.timeScale().subscribeVisibleLogicalRangeChange((range) => {
if (!range || syncing) return;
syncing = true;
indicatorChart.timeScale().setVisibleLogicalRange(range);
syncing = false;
});
indicatorChart.timeScale().subscribeVisibleLogicalRangeChange((range) => {
if (!range || syncing) return;
syncing = true;
priceChart.timeScale().setVisibleLogicalRange(range);
syncing = false;
});
对于同一图表中的 v5 窗格,优先使用 chart.addSeries(SeriesType, options, paneIndex) 和 chart.panes()[i].setHeight(px)。如果原始窗格可能移动,请保留 IPaneApi 引用,并调用 pane.paneIndex(),不要永远假定索引为 0。
坐标转换
chart.subscribeClick((param) => {
if (!param.point || param.time === undefined) return;
const price = series.coordinateToPrice(param.point.y);
const logical = chart.timeScale().coordinateToLogical(param.point.x);
if (price === null || logical === null) return;
// Store { time: param.time, price } or convert logical back later:
const x = chart.timeScale().logicalToCoordinate(logical);
const y = series.priceToCoordinate(price);
});
绘图工具和注释请使用公开的转换 API。仅凭 DOM 画布坐标无法确定图表价格/时间。
Next.js 仅客户端组件
'use client';
import { createChart, LineSeries } from 'lightweight-charts';
import type { ISeriesApi, LineData, Time } from 'lightweight-charts';
import { useEffect, useRef } from 'react';
export function LwcChart({ data }: { data: LineData<Time>[] }) {
const ref = useRef<HTMLDivElement | null>(null);
const seriesRef = useRef<ISeriesApi<'Line'> | null>(null);
useEffect(() => {
if (!ref.current) return;
const chart = createChart(ref.current, { autoSize: true });
const series = chart.addSeries(LineSeries);
seriesRef.current = series;
return () => {
seriesRef.current = null;
chart.remove();
};
}, []);
useEffect(() => {
seriesRef.current?.setData(data);
}, [data]);
return <div ref={ref} style={{ width: '100%', height: 320 }} />;
}
在服务端渲染的 Next.js 页面中,使用以下方式导入组件:
import dynamic from 'next/dynamic';
const LwcChart = dynamic(() => import('./LwcChart').then((m) => m.LwcChart), {
ssr: false,
});
加载纯 HTML
没有打包器时,请使用独立的 IIFE 构建:
<div id="chart" style="width: 600px; height: 300px"></div>
<script src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"></script>
<script>
const chart = LightweightCharts.createChart(document.getElementById('chart'));
const series = chart.addSeries(LightweightCharts.LineSeries);
</script>
根据环境选择加载方式:
- 打包器(Vite/webpack/Next): 使用裸
import { createChart } from 'lightweight-charts'。软件包的exports会解析到正确的 ESM/CJS 构建。 - 浏览器
<script>(无打包器): 上面的独立 IIFE 构建会公开LightweightCharts全局对象;这里不会解析裸模块说明符。 - 浏览器原生 ESM(
<script type="module">): 从具体的.mjsURL(例如独立.mjs)导入,或添加导入映射;裸'lightweight-charts'说明符无法解析。 - SSR 框架: 仅在客户端加载(参见上面的 Next.js 示例)——切勿在服务端组件的模块顶层导入。
插件入门
npm create lwc-plugin@latest
请以生成的项目和 plugin-examples/ 为基础。首先确定扩展类型:
- 原语(
IPanePrimitive/ISeriesPrimitive,通过attachPrimitive附加)——用于绘图、叠加层、标签、带状区域、注释和命中测试。这是默认选择;除非需要真正的序列行为,否则请使用它。 - 自定义序列(
ICustomSeriesPaneView)——仅当扩展需要自己的数据、自动缩放或价格/时间刻度集成时使用。它更复杂;不要将其用于装饰。
对于可拖动的绘图,请使用 series.attachPrimitive(...) 或 pane.attachPrimitive(...) 附加原语,然后通过 subscribeClick / subscribeCrosshairMove 和坐标转换 API 管理交互。从 fancy-canvas 导入仅用于渲染器的 CanvasRenderingTarget2D。渲染器接口是 IPrimitivePaneRenderer(不是 IPanePrimitivePaneRenderer)。
非金融数据
import { createOptionsChart } from 'lightweight-charts';
const chart = createOptionsChart(container);
首先确定水平轴是否确实为非时间轴:
- 真正的自定义水平刻度(期权链、按非时间键排列的传感器扫描):使用
createOptionsChart创建数值 x 轴,或使用带有自定义IHorzScaleBehavior的createChartEx(请在本地类型定义中核实两者)。 - 仅 y 轴单位非金融(温度、负载),使用常规时间/类别轴:保留普通的
createChart序列模型,并设置priceFormat/localization.priceFormatter,使标签符合数据领域。 - 实际有序的分类 x 轴:将类别映射为升序的
BusinessDay字符串,比使用自定义刻度更简单——但请说明此时的轴是日期形式,而非真正的分类轴。
自定义价格格式化器
chart.applyOptions({
localization: {
priceFormatter: (p: number) => `$${p.toFixed(2)}`,
},
});
如需按序列设置格式,请在序列选项中设置 priceFormat: { type: 'custom', formatter, minMove }——图表级别的 priceFormatter 是回退选项。
要恢复内置格式,请传入 null:chart.applyOptions({ localization: { priceFormatter: null } })。传入 undefined 会保留当前格式化器。
最小窗格原语
import type {
IPanePrimitive,
IPanePrimitivePaneView,
IPrimitivePaneRenderer,
Time,
} from 'lightweight-charts';
import type { CanvasRenderingTarget2D } from 'fancy-canvas';
class Overlay implements IPanePrimitive<Time> {
paneViews(): IPanePrimitivePaneView[] { return [new View()]; }
}
class View implements IPanePrimitivePaneView {
renderer(): IPrimitivePaneRenderer { return new Renderer(); }
}
class Renderer implements IPrimitivePaneRenderer {
draw(target: CanvasRenderingTarget2D): void {
target.useMediaCoordinateSpace(({ context, mediaSize }) => {
context.fillStyle = 'rgba(0,0,0,0.05)';
context.fillRect(0, 0, mediaSize.width, mediaSize.height);
});
}
}
chart.panes()[0].attachPrimitive(new Overlay());
可运行示例位于 plugin-examples/src/plugins/ 下——从那里复制结构,再从头编写。
示例
“每次收到新数据时,我的图表都会跳到最右侧。”
- **涉及的层:**数据模型(4)和时间刻度(3)。
- **疑点:**代码在每次更新时都调用
series.setData(...),而不是series.update(...)。setData会重置可见范围。 - **验证:**询问调用路径使用的是
setData还是update。如果是setData,询问是否在调用前捕获并在调用后恢复可见逻辑范围——这是 v4 时代的变通方案。 - **修复:**增量更新时改用
series.update(bar);仅在替换全部历史数据时使用setData;只有用户明确希望始终跟随最新数据时,才使用chart.timeScale().scrollToRealTime()。 - 参考:
website/tutorials/demos/realtime-updates.js、website/docs/time-scale.md。
代码生成规则
- **默认使用 v5。**除非用户安装的包或提示词指定了较旧版本,否则假设使用 v5 API。如果用户使用的是 v4,请说明迁移到 v5 的要点,而不要混用语法。
- **使用真实的选项名称。**在使用方应用中,搜索
node_modules/lightweight-charts/dist/typings.d.ts;在上游仓库中,搜索dist/typings.d.ts或src/api/options/。图表、序列和刻度中存在许多名称相似的选项——请确认选项属于哪个层级。 - **提供最精简的代码片段。**每个代码块只展示一个功能。在一个代码片段中组合标记、水印和自定义窗格原语,会让人难以分辨各个 API 的用途。
- **匹配用户的框架。**使用 React 的用户需要
useEffect生命周期;使用原生 JavaScript 的用户则不需要。 - **不要凭空编造。**如果某个 API 名称未出现在已安装的类型定义或上游源码中,它就不存在。
回答规范
回答 lightweight-charts 相关问题时:
- 指明相关的 v5 API。
- 提供一个最精简的代码片段,而非大型演示。
- 指出该任务中最容易踩的坑。
- 说明检查了哪些本地源码(版本/类型定义),或声明无法验证。