lightweight-charts について
lightweight-chartsは、下流のnpmアプリと上流のソースリポジトリの両方で、lightweight-charts APIの利用を支援するスキルです。ローカルの型定義を優先して確認し、v5の使い方や移行方法を案内します。
主な機能
- 01ローカルの型定義に基づくAPI確認
- 02npm利用アプリとソースリポジトリの判別
- 03v5のチャート、シリーズ、ペインの説明
- 04時間、操作、リアルタイム更新の問題調査
- 05v4 APIからv5への置き換え案内
活用シーン
- 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で確認します。 - API の範囲は
node_modules/lightweight-charts/dist/typings.d.tsで確認します。
- 実際のバージョンは
- 上流リポジトリでは、まず
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 ウィンドウラッパーについて述べている場合は、TypeScript パッケージではなくサードパーティ製の Python ラッパーを使っている可能性があります。lightweight-charts v5 の JavaScript に関する基本的なアドバイスを提示する前に、その点を明確に伝えてください。
基本モデル
依存関係の順に並べた 8 つのレイヤーです。多くの不具合は、これらを混同することで発生します。
- チャート —
createChart(container, options)はIChartApiを返します。1 つのコンテナー要素につきチャートは 1 つです。 - シリーズ —
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チャートオプションに代わるものです。- シリーズ型はツリーシェイクされます。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} |
| 2 つのスケール/反転 | 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/ |
| 座標変換/ヒットテスト | subscribeClick、coordinateToPrice、timeScale().coordinateToLogical の dist/typings.d.ts |
| 非時間軸の水平スケール/オプションチャート | createOptionsChart、createChartEx、IHorzScaleBehavior の dist/typings.d.ts |
| ピクセル単位の正確なレンダリング | 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(または独自のツールチップフォーマッター)を使用してください。DST に安全な IANA タイムゾーンのフォーマットには、Intl.DateTimeFormat(..., { timeZone })、Luxon、または date-fns-tz を使用してください。 - タイムスタンプを事前にシフトすると、チャートの意味が変わります。 選択したタイムゾーンに目盛りを合わせられますが、UTC の時間軸上でのバーの位置も変わります。ユーザーが意図的にデータのシフトを望んでいる場合を除き、フォーマッターによる表示を優先してください。
- シリーズデータは
timeの昇順で厳密に並び、値が重複していてはいけません。 重複したデータは通知なしに置き換えられ、順序が正しくないポイントは破棄されるか、エラーになります。 - シリーズごとに使用できる時刻形式は 1 種類です。
BusinessDay('YYYY-MM-DD'文字列または{ year, month, day })かUTCTimestampを使用できますが、1 つのシリーズ内で混在させないでください。 - 空白ポイントには
timeのみを指定します(value/open/… は指定しません)。間隔を空けたり、オーバーレイを整列させたりするために使用してください。値にnullを設定しないでください。 setDataはデータセットを置き換え、表示範囲をリセットすることがあります。update(point)はtime > lastの場合は追加し、time === lastの場合は置き換えます。update(point, true)は既存の過去のポイントを更新できますが、処理が遅く、欠落している過去のポイントは挿入しません。過去のデータを先頭に追加するには、新しい配列を作成してsetDataを再度呼び出してください。先頭に追加するメソッドはありません。チャートの表示位置が変わらないように、表示中の論理範囲を保存して復元してください。timeScale.setVisibleLogicalRangeは論理範囲(バーのインデックス)を指定するもので、時刻ベースではありません。 時刻の範囲を指定するにはsetVisibleRangeを、リセットするにはfitContent()を使用してください。
スケールとペイン
- 価格スケールを 2 つ表示するには、シリーズに
priceScaleId: 'right'/'left'を割り当て、左側のスケールを表示可能にする必要があります。chart.applyOptions({ leftPriceScale: { visible: true }, rightPriceScale: { visible: true } })またはchart.priceScale('left').applyOptions({ visible: true })を使用してください。 - オーバーレイシリーズ(
priceScaleId: ''または任意のカスタム ID)には、デフォルトで自動スケーリングされる非表示のスケールが割り当てられます。軸ラベルを表示する場合は、明示的に表示してください。 autoscaleInfoProviderはレイアウト処理のたびに実行されます。 処理を軽量にし、呼び出しごとのメモリ割り当ては避けてください。addSeries(_, _, paneIndex)は、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 チェックを行ってください。param.seriesData.get(series)は、バー間または最初のバーより前ではundefinedを返します。- クリック/クロスヘアの座標は API で変換する必要があります。
series.coordinateToPrice(y)/series.priceToCoordinate(price)とchart.timeScale().coordinateToLogical(x)/logicalToCoordinate(logical)/timeToCoordinate(time)を使用してください。Canvas の DOM ジオメトリから価格や時刻を推測しないでください。
プラグインとカスタムレンダリング
- スキャフォールドやサンプルからプラグインを始めてください。 プリミティブをゼロから作成する前に、
npm create lwc-plugin@latestとplugin-examples/の利用をおすすめします。 - インタラクティブな描画ツールには2つの要素が必要です。 描画用のプリミティブ/カスタムシリーズと、公開 API で座標を変換するチャートのインタラクションハンドラー(
subscribeClick、subscribeCrosshairMove、ドラッグ状態)です。 CanvasRenderingTarget2Dはlightweight-chartsではなく、fancy-canvasからインポートします。- ピクセルに揃った線には
target.useBitmapCoordinateSpace(scope => …)を使用し、CSS ピクセル単位のロジックにはtarget.useMediaCoordinateSpace(scope => …)を使用します。これらを混在させると、HiDPI ディスプレイでぼやけたり、サブピクセルのジッターが発生したりします。 IPanePrimitiveのビューはペイン全体に描画され、ISeriesPrimitiveのビューはシリーズ内にクリップされます。 適切な基底クラスを選んでください。- レンダラーのインターフェースは
IPanePrimitivePaneRendererではなくIPrimitivePaneRendererです。 ビューは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 を呼び出します。
2つの価格スケール(左+右)
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;
});
1つのチャート内にある v5 ペインには、chart.addSeries(SeriesType, options, paneIndex) と chart.panes()[i].setHeight(px) を優先して使用してください。元のペインが移動する可能性がある場合は、IPaneApi の参照を保持し、インデックスが常に 0 だと仮定せずに pane.paneIndex() を呼び出してください。
座標変換
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 を使用して操作を管理します。レンダラー専用の CanvasRenderingTarget2D は fancy-canvas からインポートしてください。レンダラーインターフェースは IPrimitivePaneRenderer です(IPanePrimitivePaneRenderer ではありません)。
金融以外のデータ
import { createOptionsChart } from 'lightweight-charts';
const chart = createOptionsChart(container);
まず、水平軸が本当に時間軸ではないかどうかを判断してください。
- 真のカスタム水平スケール(オプションチェーン、時間以外のキーによるセンサーのスイープ):数値 x 軸には
createOptionsChartを、カスタムの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.update(...)ではなくseries.setData(...)を呼び出しています。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/を grep します。チャート、シリーズ、スケールには名前が似たオプションが多数あるため、そのオプションがどの階層に属するか確認してください。 - 最小限のスニペットにします。 コードブロックごとに機能は1つだけにします。マーカー、ウォーターマーク、カスタムペインプリミティブを1つのスニペットにまとめると、各 API の役割が分かりにくくなります。
- ユーザーのフレームワークに合わせます。 React ユーザーには
useEffectのライフサイクルが必要ですが、バニラ JavaScript のユーザーには不要です。 - 作り上げないでください。 API 名がインストール済みの型定義または上流ソースに見つからない場合、その API は存在しません。
回答の要件
lightweight-charts に関する質問に答える際は、次のとおりにします。
- 関連する v5 API を示します。
- 巨大なデモではなく、最小限のスニペットを1つ示します。
- そのタスクで特に注意すべき落とし穴を挙げます。
- 確認したローカルソース(バージョン/型定義)を伝えるか、確認できなかったことを明記します。