描画ツール

DrawingController は、チャートに手作業で描画を加えるレイヤーです。ライン、図形、フィボナッチのレベル、ポジションの下書きを扱います。コントローラーは図形を純粋な JSON オブジェクトとして保持し、それをキャンバスのプリミティブに結び付け、あらゆる変更をチャートの取り消しスタックを通し、マウスによる段階的な作図も引き受けます。

組み込み

このレイヤーは @stocksharp/chart パッケージの独立したエントリーポイントとして提供されます。

import { BuiltInDrawingType, DrawingController } from '@stocksharp/chart/drawings';

このエントリーポイントをインポートすると、組み込みのすべての描画タイプが共通のカタログ drawingDefinitionRegistry に登録されます。

作成と更新

コントローラーが必要とするのはチャートだけです。コマンドスタックも既定では同じチャートから取得するため(chart.commandStack())、取り消しとやり直しはチャート上の他の操作と一緒に機能します。

import { CandlestickSeries, createChart } from '@stocksharp/chart';
import { BuiltInDrawingType, DrawingController } from '@stocksharp/chart/drawings';

const chart = createChart(document.getElementById('chart')!, { timeScale: { timeVisible: true } });
chart.addSeries(CandlestickSeries, {}).setData(candles);

const drawings = new DrawingController({ chart });

// 水平ライン: 点は 1 つ、時刻は秒単位の Unix 時刻です。
const level = drawings.create(
  BuiltInDrawingType.HorizontalLine,
  [{ time: 1_712_000_000, price: 68_000 }],
  { options: { color: '#f5c542', lineWidth: 2 } },
);

// 2 点によるトレンドライン。サブペインを指定する場合は paneId を使います。
drawings.create(
  BuiltInDrawingType.TrendLine,
  [
    { time: 1_712_000_000, price: 67_400 },
    { time: 1_712_600_000, price: 69_150 },
  ],
  { paneId: 'main' },
);

drawings.updateOptions(level.id, { lineWidth: 3 });
drawings.setLocked(level.id, true);

// セットのスナップショットは zOrder 順に並んで届きます。
drawings.subscribe(items => console.log(items.length));

chart.commandStack().undo();

create は不足しているフィールドを補います。paneId は既定で mainvisibletruelockedfalsezOrder は現在の最大値より 1 大きい値になり、オプションはそのタイプの defaultOptions の上に重ねられます。add は完成したインスタンスをそのまま挿入し、duplicate は既存のものを複製し、removeclear は削除します。これらの呼び出しはいずれも、履歴にちょうど 1 つの取り消し可能なコマンドを積みます。

update は任意のフィールドの組み合わせ(pointsoptionspaneIdvisiblelockedzOrder)を変更します。updateOptionssetVisiblesetLockedmoveToPane は、よくある場合のための短縮形です。書き込みの前にインスタンスは正規化されます。点とオプションは JSON 互換かどうかを検証されて凍結され、点の数はそのタイプのスキーマと、ペインはチャートに存在するペインと照合されます。

組み込みのタイプ

識別子は BuiltInDrawingType にまとめられており、その文字列値がそのまま、保存された図形の type フィールドになります。

定数 点の数 オプション
HorizontalLine horizontal-line 1 LineDrawingOptions
VerticalLine vertical-line 1 LineDrawingOptions
TrendLine trend-line 2 LineDrawingOptions
Ray ray 2 LineDrawingOptions
Rectangle rectangle 2 RectangleDrawingOptions
Text text 1 TextDrawingOptions
Note note 1 TextDrawingOptions
FibonacciRetracement fibonacci-retracement 2 FibonacciDrawingOptions
Measure measure 2 MeasureDrawingOptions
LongPosition long-position 3 PositionDrawingOptions
ShortPosition short-position 3 PositionDrawingOptions

オプションのセットは用途によって異なります。

  • LineDrawingOptionscolorlineWidth(範囲は (0, 20])、lineStyle(0〜4)。
  • RectangleDrawingOptions — 上記に加えて、塗りつぶし用の fillColor
  • TextDrawingOptionstext(最大 10,000 文字、改行も反映されます)、colorbackgroundColorborderColorborderWidthfontSizefontFamilypaddingNoteText と違うのは既定値だけで、背景、枠線、広めの余白が付きます。
  • FibonacciDrawingOptionslevels(範囲 [-5, 5] の値を 2 個から 32 個。重複は取り除かれ、リストは並べ替えられます)、labelsVisibleextendRight、および colorlineWidthlineStylefillColorfontSize
  • MeasureDrawingOptionscolorlineWidthfillColorlabelColorlabelBackgroundColorfontSize。ラベルには、選択した区間の価格の変化、パーセント、経過時間が表示されます。
  • PositionDrawingOptionsentryColortargetColorstopColortargetFillColorstopFillColortextColorlineWidthfontSizequantity。3 つの点は順に、エントリー、ターゲット、ストップを表し、これらからラベルの利益、リスク、R:R 比が計算されます。

型の検証を通らないオプション値は例外になります。不正な線幅や空の色を持つ図形を保存することはできません。

マウスによる作図

段階的な入力はコントローラー自身が受け持ちます。チャートを描画モードに切り替え、クリックと十字カーソルを購読します。

drawings.subscribeCreation(state => {
  if (state === null) return;                    // 作図が完了または中止されました
  console.log(state.name, state.points.length, state.minimumPoints, state.maximumPoints);
});

drawings.beginCreation(BuiltInDrawingType.Rectangle, { options: { color: '#26a69a' } });

// 図形が必要な点の数に達するまでは、Esc で中止できます。
document.addEventListener('keydown', event => {
  if (event.key === 'Escape') drawings.cancelCreation();
});

クリックのたびに、マグネットを通した点が追加されます。カーソルの移動は下書きを更新し、下書きは完成した図形と同じプリミティブで描画されますが、履歴には入りません。ペインは最初のクリックで固定され、他のペインでのクリックは無視されます。そのタイプが許す最大数まで点が集まると、作図は自動的に完了し、通常の図形が作成されます。finishCreation は作図を早めに終了し、点が最小数に満たない場合は null を返します。cancelCreation は下書きを破棄し、creation は現在のスナップショット DrawingCreationSnapshot を返します。

バーへのスナップ

マグネットは、現在のペインのシリーズの値に点を引き寄せます。計算は画面座標で、候補までの垂直距離に基づいて行われます。

import { DrawingMagnetMode } from '@stocksharp/chart/drawings';

const drawings = new DrawingController({
  chart,
  magnet: { mode: DrawingMagnetMode.Weak, maxDistance: 12 },
});

drawings.applyMagnetOptions({ mode: DrawingMagnetMode.Strong });
console.log(drawings.magnetOptions());

DrawingMagnetMode.None はスナップを無効にし、Weak(既定のモード)は maxDistance(既定は 10 CSS ピクセル)の範囲内でだけ引き寄せ、Strong は常に最も近い値へ引き寄せます。作図中に設定を変更すると、プレビューの点はすぐに再計算されます。

保存と復元

DrawingInstance は意図的に実行時のオブジェクトを含まないため、描画のセットはそのままシリアライズできます。

import type { DrawingInstance } from '@stocksharp/chart/drawings';

const saved = JSON.stringify(drawings.drawings());

const result = drawings.replaceAll(JSON.parse(saved) as DrawingInstance[], { unknownType: 'skip' });
console.log(result.restored.length, result.skipped);

replaceAll はセット全体を置き換えます。まず入力されたすべてのインスタンスが検証され(識別子の重複はエラーです)、次に古い図形がチャートから外され、新しいものが追加されます。1 つでも配置できなかった場合は、直前の状態が復元されます。未知の type は、ポリシーが skip(既定)なら理由 unknown-type とともに skipped に入り、error なら復元を中断します。復元はコマンド履歴を消去するため、トランザクションの内側で呼び出すことはできません。

独自の描画タイプ

タイプのカタログは拡張できます。定義を記述して、プリミティブへのバインディングを返すだけで済みます。選択、ハンドル、ドラッグを備えた既製の外枠は createInteractiveDrawingBinding が提供します。

import { createInteractiveDrawingBinding, registerDrawing } from '@stocksharp/chart/drawings';

registerDrawing({
  type: 'price-band',
  name: 'Price Band',
  points: { min: 2, max: 2 },
  defaultOptions: { color: '#4a9eff' },
  normalizeOptions: options => Object.freeze({ color: String(options.color).trim() }),
  create: (instance, events) => createInteractiveDrawingBinding(instance, events, {
    draw(context) {
      const [first, second] = context.points;
      if (second === undefined) return;
      context.context.strokeStyle = String(context.instance.options.color);
      context.context.strokeRect(
        context.plot.x, Math.min(first.y, second.y),
        context.plot.width, Math.abs(second.y - first.y),
      );
    },
    hitTest(point, context) {
      const [first, second] = context.points;
      if (second === undefined) return null;
      return point.y >= Math.min(first.y, second.y) && point.y <= Math.max(first.y, second.y)
        ? { cursor: 'move' }
        : null;
    },
  }),
});

drawings.create('price-band', [
  { time: 1_712_000_000, price: 67_800 },
  { time: 1_712_600_000, price: 68_900 },
]);

draw は、画面上の点、描画領域の矩形、テーマ、スケール係数、選択状態を受け取ります。hitTest は、カーソルが図形の本体に入っているかどうかを返します。任意の autoscaleInfohandleColor は、自動スケーリングへの参加とハンドルの色を指定します。normalizeOptions はモデルへの書き込みのたびに呼ばれます。オプション値の検証を行うべき唯一の場所です。

本体や個々の点のドラッグは、preview(中間状態。履歴には書き込まれません)、commit(「Edit drawing」という 1 つのコマンド)、cancel(ジェスチャー前の状態への復帰)のイベントを通じて行われます。ロックされた図形(locked)はドラッグできず、ハンドルも表示されません。

カタログは直接操作することもできます。unregisterDrawing(type)getDrawingDefinition(type)getDrawingTypes() があり、DrawingDefinitionRegistry を使えば独自のカタログを用意して、registry パラメーターでコントローラーに渡せます。

公開メソッド

DrawingController:

  • drawings()get(id)has(id) — 現在のセットの読み取り。
  • create(type, points, options?)add(instance)duplicate(id, duplicateId?) — 図形の追加。
  • update(id, patch)updateOptions(id, patch)setVisible(id, visible)setLocked(id, locked)moveToPane(id, paneId) — 変更。
  • remove(id)clear() — 削除。
  • beginCreation(type, options?)finishCreation()cancelCreation()creation() — マウスによる作図。
  • magnetOptions()applyMagnetOptions(patch) — バーへのスナップ。
  • replaceAll(instances, options?) — 保存したセットの復元。
  • subscribe(listener) / unsubscribe(listener)subscribeCreation(listener) / unsubscribeCreation(listener) — 購読。
  • dispose() — リソースを解放します。

コンストラクターは chart(必須)のほか、registrycommandStackidFactorymagnet を受け取ります。

エントリーポイントは、このレイヤーの残りの部分もエクスポートしています。スナップを自前で計算するための DrawingMagnetcreateInteractiveDrawingBinding とセットの InteractiveDrawingPrimitive、検証用の関数 normalizeDrawingInstancenormalizeDrawingOptions、定義の既製セット builtInLineDrawingDefinitionsbuiltInShapeDrawingDefinitionsbuiltInAnalysisDrawingDefinitionsbuiltInPositionDrawingDefinitions、そしてそれらを独自のカタログに登録するための対になる関数 registerBuiltInLineDrawingsregisterBuiltInShapeDrawingsregisterBuiltInAnalysisDrawingsregisterBuiltInPositionDrawings です。

関連項目