@baron1996/klinecharts-adapter 0.9.4 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"id-map.d.ts","sourceRoot":"","sources":["../../src/conversion/id-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,aAAa,CAAC;AAOhD,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpD,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtD;AAMD,gCAAgC;AAChC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,WAAW,CAqC9E;AAED,wBAAgB,eAAe,CAC9B,GAAG,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,MAAM,CAMR"}
1
+ {"version":3,"file":"id-map.d.ts","sourceRoot":"","sources":["../../src/conversion/id-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,aAAa,CAAC;AAYhD,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpD,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtD;AAMD,gCAAgC;AAChC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,WAAW,CAyC9E;AAED,wBAAgB,eAAe,CAC9B,GAAG,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,MAAM,CAMR"}
@@ -1,4 +1,5 @@
1
1
  import { SceneError } from '@baron1996/kline-scene-schema';
2
+ import { GAP_AWARE_CANDLE_PANE_ID, isGapAwareScene, } from '../gap-aware-series.js';
2
3
  function invert(source) {
3
4
  return new Map(Array.from(source, ([sceneId, engineId]) => [engineId, sceneId]));
4
5
  }
@@ -11,7 +12,11 @@ export function createEngineIdMap(scene, chart) {
11
12
  if (pane === undefined) {
12
13
  continue;
13
14
  }
14
- const enginePaneId = pane.kind === 'candle' ? 'candle_pane' : `baron_pane_${paneIndex}`;
15
+ const enginePaneId = pane.kind === 'candle'
16
+ ? isGapAwareScene(scene)
17
+ ? GAP_AWARE_CANDLE_PANE_ID
18
+ : 'candle_pane'
19
+ : `baron_pane_${paneIndex}`;
15
20
  paneToEngine.set(pane.id, enginePaneId);
16
21
  for (let axisIndex = 0; axisIndex < pane.yAxes.length; axisIndex++) {
17
22
  const axis = pane.yAxes[axisIndex];
@@ -27,6 +27,21 @@ export interface EngineDrawingStartRequest {
27
27
  readonly metadata?: NonNullable<Drawing['metadata']>;
28
28
  readonly text?: string;
29
29
  }
30
+ export interface DrawingHitTolerance {
31
+ readonly body: number;
32
+ readonly anchor: number;
33
+ }
34
+ /** 宿主可选的 Drawing 输入策略;默认继续使用 KLineCharts 原生交互。 */
35
+ export interface DrawingInteractionOptions {
36
+ readonly touch?: 'native' | 'precision-cursor';
37
+ /** 选中 Drawing 后是否独占图表输入,直到显式取消选择。 */
38
+ readonly exclusiveSelection?: boolean;
39
+ /** CSS 像素命中半径;未配置项分别使用桌面 12/14、触摸 22/24。 */
40
+ readonly hitTolerance?: {
41
+ readonly mouse?: Partial<DrawingHitTolerance>;
42
+ readonly touch?: Partial<DrawingHitTolerance>;
43
+ };
44
+ }
30
45
  export type EngineDrawingEventType = 'created' | 'updated' | 'removed' | 'selected' | 'deselected' | 'edit-candidate';
31
46
  export interface EngineDrawingEvent {
32
47
  readonly type: EngineDrawingEventType;
@@ -1 +1 @@
1
- {"version":3,"file":"engine-port.d.ts","sourceRoot":"","sources":["../../src/drawing/engine-port.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine-port.d.ts","sourceRoot":"","sources":["../../src/drawing/engine-port.ts"],"names":[],"mappings":"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"}
package/dist/engine.d.ts CHANGED
@@ -6,6 +6,16 @@ export interface EngineHandle {
6
6
  readonly module: KLineChartsModule;
7
7
  /** 显式复位引擎点击仲裁状态;每次绘制开始前调用,避免快速连续绘制的首击被吞。 */
8
8
  readonly resetClickArbitration: () => void;
9
+ /** 在引擎坐标系内移动鼠标语义光标,用于触摸精确绘制预览。 */
10
+ readonly dispatchMouseMove: (event: EngineMouseInteraction) => void;
11
+ /** 在引擎坐标系内触发单击语义,用于触摸精确绘制落点。 */
12
+ readonly dispatchMouseClick: (event: EngineMouseInteraction) => void;
13
+ }
14
+ export interface EngineMouseInteraction {
15
+ readonly x: number;
16
+ readonly y: number;
17
+ readonly pageX: number;
18
+ readonly pageY: number;
9
19
  }
10
20
  /** 按固定顺序创建并初始化唯一的 KLineCharts 引擎。 */
11
21
  export declare function createEngine(container: HTMLElement, scene: ChartScene, options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAUzC,MAAM,MAAM,iBAAiB,GAAG,cAAc,aAAa,CAAC,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,4CAA4C;IAC5C,QAAQ,CAAC,qBAAqB,EAAE,MAAM,IAAI,CAAC;CAC3C;AA+CD,qCAAqC;AACrC,wBAAsB,YAAY,CACjC,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,YAAY,CAAC,CAsCvB"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAWzC,MAAM,MAAM,iBAAiB,GAAG,cAAc,aAAa,CAAC,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,4CAA4C;IAC5C,QAAQ,CAAC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAC3C,kCAAkC;IAClC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACpE,gCAAgC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACrE;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAqFD,qCAAqC;AACrC,wBAAsB,YAAY,CACjC,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,YAAY,CAAC,CAyCvB"}
package/dist/engine.js CHANGED
@@ -1,7 +1,29 @@
1
1
  import { SceneError } from '@baron1996/kline-scene-schema';
2
2
  import { toKLineChartsOptions } from './conversion/chart-options.js';
3
3
  import { createStaticDataLoader } from './static-data-loader.js';
4
+ import { engineDataForScene } from './gap-aware-series.js';
4
5
  import { KLINECHARTS_ENGINE_VERSION, KLINECHARTS_RUNTIME_VERSION, SUPPORTED_KLINECHARTS_RUNTIME_VERSIONS, } from './version.js';
6
+ function resolveMouseInteractionDispatch(chart) {
7
+ const chartEvent = chart._chartEvent;
8
+ if (chartEvent === undefined ||
9
+ typeof chartEvent.mouseMoveEvent !== 'function' ||
10
+ typeof chartEvent.mouseClickEvent !== 'function') {
11
+ throw new SceneError('RUNTIME_INIT_FAILED', '/runtime', `KLineCharts ${KLINECHARTS_ENGINE_VERSION} 内部鼠标语义派发钩子不可用;引擎私有结构可能已变化。`);
12
+ }
13
+ const compatEvent = (event) => ({
14
+ ...event,
15
+ isTouch: false,
16
+ preventDefault: () => undefined,
17
+ });
18
+ return {
19
+ move: (event) => {
20
+ chartEvent.mouseMoveEvent(compatEvent(event));
21
+ },
22
+ click: (event) => {
23
+ chartEvent.mouseClickEvent(compatEvent(event));
24
+ },
25
+ };
26
+ }
5
27
  function resolveClickArbitrationReset(chart) {
6
28
  const eventHandler = chart
7
29
  ._chartEvent?._event;
@@ -41,10 +63,13 @@ export async function createEngine(container, scene, options) {
41
63
  ...(scene.symbol.name === undefined ? {} : { name: scene.symbol.name }),
42
64
  });
43
65
  chart.setPeriod(structuredClone(scene.period));
44
- chart.setDataLoader(createStaticDataLoader(scene.data));
66
+ chart.setDataLoader(createStaticDataLoader(engineDataForScene(scene)));
67
+ const mouseInteraction = resolveMouseInteractionDispatch(chart);
45
68
  return {
46
69
  chart,
47
70
  module: engine,
48
71
  resetClickArbitration: resolveClickArbitrationReset(chart),
72
+ dispatchMouseMove: mouseInteraction.move,
73
+ dispatchMouseClick: mouseInteraction.click,
49
74
  };
50
75
  }
@@ -0,0 +1,44 @@
1
+ import type { ChartScene, MarketData, MarketDataGap } from '@baron1996/kline-scene-schema';
2
+ import type { Chart, IndicatorTemplate, KLineData } from 'klinecharts';
3
+ export declare const GAP_AWARE_CANDLE_INDICATOR_ID = "baron_gap_aware_candle";
4
+ export declare const GAP_AWARE_CANDLE_INDICATOR_NAME = "BARON_GAP_AWARE_CANDLE";
5
+ export declare const GAP_AWARE_CANDLE_PANE_ID = "baron_gap_aware_candle_pane";
6
+ export declare const GAP_AWARE_CANDLE_Y_AXIS_ID = "baron_gap_aware_candle_y_axis";
7
+ export type GapAwareTimelineItem = {
8
+ readonly kind: 'bar';
9
+ readonly bar: MarketData;
10
+ } | {
11
+ readonly kind: 'gap';
12
+ readonly gap: MarketDataGap;
13
+ };
14
+ export interface GapAwareCarrierData extends KLineData {
15
+ /** 仅供 Adapter 内部绘制与十字线识别,不属于公开 MarketData。 */
16
+ readonly __baronTimelineItem: GapAwareTimelineItem;
17
+ }
18
+ interface GapAwareCandleValue {
19
+ readonly open: number | null;
20
+ readonly high: number | null;
21
+ readonly low: number | null;
22
+ readonly close: number | null;
23
+ }
24
+ interface GapAwareCandleStyles {
25
+ readonly upColor: string;
26
+ readonly downColor: string;
27
+ readonly noChangeColor: string;
28
+ readonly upWickColor: string;
29
+ readonly downWickColor: string;
30
+ readonly noChangeWickColor: string;
31
+ }
32
+ export declare function isGapAwareScene(scene: ChartScene): boolean;
33
+ export declare function timelineSlotCount(scene: ChartScene): number;
34
+ export declare function gapCount(scene: ChartScene): number;
35
+ /** 将真实 Bar 与 Gap 合并为严格时间序的引擎索引载体。 */
36
+ export declare function toGapAwareCarrierData(scene: ChartScene): GapAwareCarrierData[];
37
+ export declare function engineDataForScene(scene: ChartScene): readonly KLineData[];
38
+ export declare function timelineItemOf(data: KLineData | undefined): GapAwareTimelineItem | undefined;
39
+ export declare const gapAwareCandleIndicatorTemplate: IndicatorTemplate<GapAwareCandleValue, never, GapAwareCandleStyles>;
40
+ /** 初始化仅绘制真实 Bar 的主序列;Gap 只保留横轴槽位。 */
41
+ export declare function installGapAwareMainSeries(scene: ChartScene, chart: Chart, registerIndicator: typeof import('klinecharts').registerIndicator): void;
42
+ export declare function assertGapAwareSceneSupported(scene: ChartScene): void;
43
+ export {};
44
+ //# sourceMappingURL=gap-aware-series.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gap-aware-series.d.ts","sourceRoot":"","sources":["../src/gap-aware-series.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EACX,KAAK,EAEL,iBAAiB,EACjB,SAAS,EACT,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,6BAA6B,2BAA2B,CAAC;AACtE,eAAO,MAAM,+BAA+B,2BAA2B,CAAC;AACxE,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AACtE,eAAO,MAAM,0BAA0B,kCAAkC,CAAC;AAE1E,MAAM,MAAM,oBAAoB,GAC7B;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACrD,8CAA8C;IAC9C,QAAQ,CAAC,mBAAmB,EAAE,oBAAoB,CAAC;CACnD;AAED,UAAU,mBAAmB;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,UAAU,oBAAoB;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACnC;AAMD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAE3D;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;AAED,qCAAqC;AACrC,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,UAAU,GACf,mBAAmB,EAAE,CAgCvB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,SAAS,EAAE,CAI1E;AAED,wBAAgB,cAAc,CAC7B,IAAI,EAAE,SAAS,GAAG,SAAS,GACzB,oBAAoB,GAAG,SAAS,CAElC;AAkCD,eAAO,MAAM,+BAA+B,EAAE,iBAAiB,CAC9D,mBAAmB,EACnB,KAAK,EACL,oBAAoB,CA4FpB,CAAC;AA4BF,qCAAqC;AACrC,wBAAgB,yBAAyB,CACxC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,KAAK,EACZ,iBAAiB,EAAE,cAAc,aAAa,EAAE,iBAAiB,GAC/D,IAAI,CAkBN;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAgBpE"}
@@ -0,0 +1,221 @@
1
+ import { SceneError } from '@baron1996/kline-scene-schema';
2
+ export const GAP_AWARE_CANDLE_INDICATOR_ID = 'baron_gap_aware_candle';
3
+ export const GAP_AWARE_CANDLE_INDICATOR_NAME = 'BARON_GAP_AWARE_CANDLE';
4
+ export const GAP_AWARE_CANDLE_PANE_ID = 'baron_gap_aware_candle_pane';
5
+ export const GAP_AWARE_CANDLE_Y_AXIS_ID = 'baron_gap_aware_candle_y_axis';
6
+ function adapterError(path, message) {
7
+ return new SceneError('RUNTIME_INIT_FAILED', path, message);
8
+ }
9
+ export function isGapAwareScene(scene) {
10
+ return scene.version === 2;
11
+ }
12
+ export function timelineSlotCount(scene) {
13
+ return scene.data.length + (scene.gaps?.length ?? 0);
14
+ }
15
+ export function gapCount(scene) {
16
+ return scene.gaps?.length ?? 0;
17
+ }
18
+ /** 将真实 Bar 与 Gap 合并为严格时间序的引擎索引载体。 */
19
+ export function toGapAwareCarrierData(scene) {
20
+ if (!isGapAwareScene(scene) || scene.gaps === undefined) {
21
+ throw adapterError('/gaps', 'Gap-aware carrier requires a ChartScene v2 gaps array.');
22
+ }
23
+ const carriers = [];
24
+ let barIndex = 0;
25
+ let gapIndex = 0;
26
+ while (barIndex < scene.data.length || gapIndex < scene.gaps.length) {
27
+ const bar = scene.data[barIndex];
28
+ const gap = scene.gaps[gapIndex];
29
+ if (gap === undefined || (bar !== undefined && bar.timestamp < gap.timestamp)) {
30
+ const snapshot = structuredClone(bar);
31
+ carriers.push({
32
+ ...snapshot,
33
+ __baronTimelineItem: { kind: 'bar', bar: snapshot },
34
+ });
35
+ barIndex += 1;
36
+ continue;
37
+ }
38
+ const snapshot = structuredClone(gap);
39
+ carriers.push({
40
+ timestamp: snapshot.timestamp,
41
+ open: 0,
42
+ high: 0,
43
+ low: 0,
44
+ close: 0,
45
+ volume: 0,
46
+ __baronTimelineItem: { kind: 'gap', gap: snapshot },
47
+ });
48
+ gapIndex += 1;
49
+ }
50
+ return carriers;
51
+ }
52
+ export function engineDataForScene(scene) {
53
+ return isGapAwareScene(scene)
54
+ ? toGapAwareCarrierData(scene)
55
+ : structuredClone(scene.data);
56
+ }
57
+ export function timelineItemOf(data) {
58
+ return data?.__baronTimelineItem;
59
+ }
60
+ function directionOf(value) {
61
+ if (value.close > value.open) {
62
+ return 'up';
63
+ }
64
+ if (value.close < value.open) {
65
+ return 'down';
66
+ }
67
+ return 'flat';
68
+ }
69
+ function bodyColor(styles, direction) {
70
+ return direction === 'up'
71
+ ? styles.upColor
72
+ : direction === 'down'
73
+ ? styles.downColor
74
+ : styles.noChangeColor;
75
+ }
76
+ function wickColor(styles, direction) {
77
+ return direction === 'up'
78
+ ? styles.upWickColor
79
+ : direction === 'down'
80
+ ? styles.downWickColor
81
+ : styles.noChangeWickColor;
82
+ }
83
+ export const gapAwareCandleIndicatorTemplate = {
84
+ name: GAP_AWARE_CANDLE_INDICATOR_NAME,
85
+ shortName: '',
86
+ series: 'price',
87
+ shouldOhlc: false,
88
+ shouldFormatBigNumber: false,
89
+ figures: [
90
+ // 只参与 Y 轴范围计算;没有 type 就不会创建引擎 Figure。
91
+ { key: 'low' },
92
+ {
93
+ key: 'high',
94
+ type: 'bar',
95
+ attrs({ data, coordinate, yAxis }) {
96
+ if (data.current == null || data.current.close === null) {
97
+ return null;
98
+ }
99
+ const high = yAxis.convertToPixel(data.current.high);
100
+ const low = yAxis.convertToPixel(data.current.low);
101
+ return {
102
+ x: coordinate.current.x - 0.5,
103
+ y: Math.min(high, low),
104
+ width: 1,
105
+ height: Math.max(1, Math.abs(high - low)),
106
+ };
107
+ },
108
+ styles({ data, indicator }) {
109
+ if (data.current == null || data.current.close === null) {
110
+ return null;
111
+ }
112
+ return {
113
+ style: 'fill',
114
+ color: wickColor(indicator.extendData, directionOf(data.current)),
115
+ };
116
+ },
117
+ },
118
+ {
119
+ key: 'close',
120
+ type: 'bar',
121
+ attrs({ data, coordinate, barSpace, yAxis }) {
122
+ if (data.current == null || data.current.close === null) {
123
+ return null;
124
+ }
125
+ const width = Math.max(1, barSpace.bar * 0.62);
126
+ const open = yAxis.convertToPixel(data.current.open);
127
+ const close = yAxis.convertToPixel(data.current.close);
128
+ const top = Math.min(open, close);
129
+ return {
130
+ x: coordinate.current.x - width / 2,
131
+ y: top,
132
+ width,
133
+ height: Math.max(1, Math.abs(open - close)),
134
+ };
135
+ },
136
+ styles({ data, indicator }) {
137
+ if (data.current == null || data.current.close === null) {
138
+ return null;
139
+ }
140
+ const color = bodyColor(indicator.extendData, directionOf(data.current));
141
+ return {
142
+ style: 'fill',
143
+ color,
144
+ borderColor: color,
145
+ borderSize: 0,
146
+ borderRadius: 0,
147
+ };
148
+ },
149
+ },
150
+ ],
151
+ calc(dataList) {
152
+ return dataList.map((data) => {
153
+ const item = timelineItemOf(data);
154
+ if (item?.kind !== 'bar') {
155
+ return { open: null, high: null, low: null, close: null };
156
+ }
157
+ return {
158
+ open: item.bar.open,
159
+ high: item.bar.high,
160
+ low: item.bar.low,
161
+ close: item.bar.close,
162
+ };
163
+ });
164
+ },
165
+ };
166
+ function indicatorCreate(scene) {
167
+ const candle = scene.chart.candle;
168
+ return {
169
+ id: GAP_AWARE_CANDLE_INDICATOR_ID,
170
+ name: GAP_AWARE_CANDLE_INDICATOR_NAME,
171
+ shortName: '',
172
+ paneId: GAP_AWARE_CANDLE_PANE_ID,
173
+ yAxisId: GAP_AWARE_CANDLE_Y_AXIS_ID,
174
+ precision: scene.symbol.pricePrecision,
175
+ visible: true,
176
+ zLevel: 0,
177
+ extendData: {
178
+ upColor: candle.upColor,
179
+ downColor: candle.downColor,
180
+ noChangeColor: candle.noChangeColor,
181
+ upWickColor: candle.upWickColor,
182
+ downWickColor: candle.downWickColor,
183
+ noChangeWickColor: candle.noChangeWickColor,
184
+ },
185
+ styles: {
186
+ lastValueMark: { show: false },
187
+ tooltip: { showRule: 'none' },
188
+ },
189
+ };
190
+ }
191
+ /** 初始化仅绘制真实 Bar 的主序列;Gap 只保留横轴槽位。 */
192
+ export function installGapAwareMainSeries(scene, chart, registerIndicator) {
193
+ if (!isGapAwareScene(scene)) {
194
+ return;
195
+ }
196
+ assertGapAwareSceneSupported(scene);
197
+ registerIndicator(gapAwareCandleIndicatorTemplate);
198
+ const createdId = chart.createIndicator(indicatorCreate(scene), true);
199
+ if (createdId !== GAP_AWARE_CANDLE_INDICATOR_ID) {
200
+ throw adapterError('/gaps', 'KLineCharts failed to create the Gap-aware main series.');
201
+ }
202
+ chart.setPaneOptions({
203
+ id: 'candle_pane',
204
+ height: 0,
205
+ minHeight: 0,
206
+ order: scene.panes.length,
207
+ state: 'minimize',
208
+ dragEnabled: false,
209
+ });
210
+ }
211
+ export function assertGapAwareSceneSupported(scene) {
212
+ if (!isGapAwareScene(scene)) {
213
+ return;
214
+ }
215
+ if (scene.chart.candle.type !== 'candle_solid') {
216
+ throw adapterError('/chart/candle/type', 'ChartScene v2 MVP only supports the candle_solid gap-aware main series.');
217
+ }
218
+ if (scene.panes.some((pane) => pane.indicators.length > 0)) {
219
+ throw adapterError('/panes', 'ChartScene v2 indicators are disabled until their Gap semantics are implemented.');
220
+ }
221
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"dragging.d.ts","sourceRoot":"","sources":["../../src/interaction/dragging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAKlE,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAyBD,wCAAwC;AACxC,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,cAAc,EAAE,MAAM,GACpB,YAAY,CAgFd"}
1
+ {"version":3,"file":"dragging.d.ts","sourceRoot":"","sources":["../../src/interaction/dragging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAKlE,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAwED,wCAAwC;AACxC,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,cAAc,EAAE,MAAM,GACpB,YAAY,CAyJd"}
@@ -13,59 +13,164 @@ function requireTimestamp(timestamps, index, path) {
13
13
  }
14
14
  return timestamp;
15
15
  }
16
+ function normalizedValue(value, pricePrecision, path) {
17
+ return normalizePriceValue(value, pricePrecision, path);
18
+ }
19
+ function timestampAtCurrentPoint(current, timestamps, path) {
20
+ return requireTimestamp(timestamps, requireDataIndex(current.dataIndex, `${path}/dataIndex`), path);
21
+ }
22
+ function translatedTimestamp(timestamp, deltaIndex, timestamps, path) {
23
+ const sourceIndex = timestamps.indexOf(timestamp);
24
+ if (sourceIndex < 0) {
25
+ throw new SceneError('INVALID_REFERENCE', path, 'Overlay point must reference an embedded bar before dragging.');
26
+ }
27
+ return requireTimestamp(timestamps, sourceIndex + deltaIndex, path);
28
+ }
29
+ function translatedPoint(point, deltaIndex, deltaValue, timestamps, pricePrecision, path) {
30
+ return {
31
+ timestamp: translatedTimestamp(point.timestamp, deltaIndex, timestamps, `${path}/timestamp`),
32
+ value: normalizedValue(point.value + deltaValue, pricePrecision, `${path}/value`),
33
+ };
34
+ }
35
+ function currentPoint(current, timestamps, pricePrecision, path) {
36
+ return {
37
+ timestamp: timestampAtCurrentPoint(current, timestamps, `${path}/timestamp`),
38
+ value: normalizedValue(current.value, pricePrecision, `${path}/value`),
39
+ };
40
+ }
16
41
  /** 根据冻结的绝对平移语义构造未提交候选,不修改输入 Overlay。 */
17
42
  export function createDragCandidate(before, dragTarget, origin, current, timestamps, pricePrecision) {
18
43
  const deltaValue = current.value - origin.value;
19
44
  if (!Number.isFinite(deltaValue)) {
20
45
  throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays', 'Drag price delta must be finite.');
21
46
  }
22
- if (before.type === 'horizontalStraightLine') {
23
- const anchor = before.anchor;
24
- if (anchor === undefined || !('value' in anchor)) {
25
- throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays/anchor', 'Missing price anchor.');
26
- }
27
- return {
28
- ...structuredClone(before),
29
- anchor: {
30
- value: normalizePriceValue(anchor.value + deltaValue, pricePrecision, '/overlays/anchor/value'),
31
- },
32
- };
33
- }
34
- if (before.type !== 'priceMeasurement' || before.start === undefined || before.end === undefined) {
35
- throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays/type', 'Controlled M2 dragging only supports horizontalStraightLine and priceMeasurement.');
36
- }
37
47
  const candidate = structuredClone(before);
38
- if (dragTarget.target === 'anchor') {
39
- if (dragTarget.anchorIndex !== 0 && dragTarget.anchorIndex !== 1) {
40
- throw new SceneError('INVALID_REFERENCE', '/overlays/anchorIndex', 'Invalid anchor index.');
48
+ const deltaIndex = requireDataIndex(current.dataIndex, '/overlays/body/dataIndex') -
49
+ requireDataIndex(origin.dataIndex, '/overlays/body/originDataIndex');
50
+ switch (before.type) {
51
+ case 'horizontalStraightLine':
52
+ case 'priceLine':
53
+ case 'simpleTag': {
54
+ const anchor = before.anchor;
55
+ if (anchor === undefined || !('value' in anchor)) {
56
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays/anchor', 'Missing price anchor.');
57
+ }
58
+ candidate.anchor = {
59
+ value: normalizedValue(dragTarget.target === 'anchor' ? current.value : anchor.value + deltaValue, pricePrecision, '/overlays/anchor/value'),
60
+ };
61
+ return candidate;
41
62
  }
42
- const index = requireDataIndex(current.dataIndex, '/overlays/anchor/dataIndex');
43
- const point = {
44
- timestamp: requireTimestamp(timestamps, index, '/overlays/anchor/timestamp'),
45
- value: normalizePriceValue(current.value, pricePrecision, '/overlays/anchor/value'),
46
- };
47
- if (dragTarget.anchorIndex === 0) {
48
- candidate.start = point;
63
+ case 'verticalStraightLine': {
64
+ const anchor = before.anchor;
65
+ if (anchor === undefined || !('timestamp' in anchor)) {
66
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays/anchor', 'Missing time anchor.');
67
+ }
68
+ candidate.anchor = {
69
+ timestamp: dragTarget.target === 'anchor'
70
+ ? timestampAtCurrentPoint(current, timestamps, '/overlays/anchor')
71
+ : translatedTimestamp(anchor.timestamp, deltaIndex, timestamps, '/overlays/anchor/timestamp'),
72
+ };
73
+ return candidate;
49
74
  }
50
- else {
51
- candidate.end = point;
75
+ case 'horizontalRayLine':
76
+ case 'horizontalSegment': {
77
+ if (before.value === undefined || before.startTimestamp === undefined ||
78
+ before.endTimestamp === undefined) {
79
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays', 'Missing horizontal line geometry.');
80
+ }
81
+ candidate.value = normalizedValue(dragTarget.target === 'anchor' ? current.value : before.value + deltaValue, pricePrecision, '/overlays/value');
82
+ if (dragTarget.target === 'anchor') {
83
+ const timestamp = timestampAtCurrentPoint(current, timestamps, '/overlays/anchor');
84
+ if (dragTarget.anchorIndex === 0)
85
+ candidate.startTimestamp = timestamp;
86
+ else if (dragTarget.anchorIndex === 1)
87
+ candidate.endTimestamp = timestamp;
88
+ else
89
+ throw new SceneError('INVALID_REFERENCE', '/overlays/anchorIndex', 'Invalid anchor index.');
90
+ }
91
+ else {
92
+ candidate.startTimestamp = translatedTimestamp(before.startTimestamp, deltaIndex, timestamps, '/overlays/startTimestamp');
93
+ candidate.endTimestamp = translatedTimestamp(before.endTimestamp, deltaIndex, timestamps, '/overlays/endTimestamp');
94
+ }
95
+ return candidate;
96
+ }
97
+ case 'verticalRayLine':
98
+ case 'verticalSegment': {
99
+ if (before.timestamp === undefined || before.startValue === undefined ||
100
+ before.endValue === undefined) {
101
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays', 'Missing vertical line geometry.');
102
+ }
103
+ candidate.timestamp = dragTarget.target === 'anchor'
104
+ ? timestampAtCurrentPoint(current, timestamps, '/overlays/anchor')
105
+ : translatedTimestamp(before.timestamp, deltaIndex, timestamps, '/overlays/timestamp');
106
+ if (dragTarget.target === 'anchor') {
107
+ const value = normalizedValue(current.value, pricePrecision, '/overlays/anchor/value');
108
+ if (dragTarget.anchorIndex === 0)
109
+ candidate.startValue = value;
110
+ else if (dragTarget.anchorIndex === 1)
111
+ candidate.endValue = value;
112
+ else
113
+ throw new SceneError('INVALID_REFERENCE', '/overlays/anchorIndex', 'Invalid anchor index.');
114
+ }
115
+ else {
116
+ candidate.startValue = normalizedValue(before.startValue + deltaValue, pricePrecision, '/overlays/startValue');
117
+ candidate.endValue = normalizedValue(before.endValue + deltaValue, pricePrecision, '/overlays/endValue');
118
+ }
119
+ return candidate;
120
+ }
121
+ case 'rayLine':
122
+ case 'segment':
123
+ case 'straightLine':
124
+ case 'fibonacciLine':
125
+ case 'priceChannelLine':
126
+ case 'parallelStraightLine':
127
+ case 'brush': {
128
+ if (before.points === undefined) {
129
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays/points', 'Missing point geometry.');
130
+ }
131
+ if (dragTarget.target === 'anchor') {
132
+ if (dragTarget.anchorIndex === null || before.points[dragTarget.anchorIndex] === undefined) {
133
+ throw new SceneError('INVALID_REFERENCE', '/overlays/anchorIndex', 'Invalid anchor index.');
134
+ }
135
+ candidate.points[dragTarget.anchorIndex] = currentPoint(current, timestamps, pricePrecision, `/overlays/points/${dragTarget.anchorIndex}`);
136
+ }
137
+ else {
138
+ candidate.points = before.points.map((point, index) => translatedPoint(point, deltaIndex, deltaValue, timestamps, pricePrecision, `/overlays/points/${index}`));
139
+ }
140
+ return candidate;
141
+ }
142
+ case 'simpleAnnotation':
143
+ case 'callout':
144
+ case 'text':
145
+ case 'crossLine': {
146
+ if (before.point === undefined) {
147
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays/point', 'Missing point geometry.');
148
+ }
149
+ candidate.point = dragTarget.target === 'anchor'
150
+ ? currentPoint(current, timestamps, pricePrecision, '/overlays/point')
151
+ : translatedPoint(before.point, deltaIndex, deltaValue, timestamps, pricePrecision, '/overlays/point');
152
+ return candidate;
153
+ }
154
+ case 'rectangle':
155
+ case 'arrow':
156
+ case 'priceMeasurement': {
157
+ if (before.start === undefined || before.end === undefined) {
158
+ throw new SceneError('SCENE_SCHEMA_INVALID', '/overlays', 'Missing two-point geometry.');
159
+ }
160
+ if (dragTarget.target === 'anchor') {
161
+ const point = currentPoint(current, timestamps, pricePrecision, '/overlays/anchor');
162
+ if (dragTarget.anchorIndex === 0)
163
+ candidate.start = point;
164
+ else if (dragTarget.anchorIndex === 1)
165
+ candidate.end = point;
166
+ else
167
+ throw new SceneError('INVALID_REFERENCE', '/overlays/anchorIndex', 'Invalid anchor index.');
168
+ }
169
+ else {
170
+ candidate.start = translatedPoint(before.start, deltaIndex, deltaValue, timestamps, pricePrecision, '/overlays/start');
171
+ candidate.end = translatedPoint(before.end, deltaIndex, deltaValue, timestamps, pricePrecision, '/overlays/end');
172
+ }
173
+ return candidate;
52
174
  }
53
- return candidate;
54
- }
55
- const startIndex = timestamps.indexOf(before.start.timestamp);
56
- const endIndex = timestamps.indexOf(before.end.timestamp);
57
- if (startIndex < 0 || endIndex < 0) {
58
- throw new SceneError('INVALID_REFERENCE', '/overlays', 'priceMeasurement endpoints must reference embedded bars before dragging.');
59
175
  }
60
- const deltaIndex = requireDataIndex(current.dataIndex, '/overlays/body/dataIndex') -
61
- requireDataIndex(origin.dataIndex, '/overlays/body/originDataIndex');
62
- candidate.start = {
63
- timestamp: requireTimestamp(timestamps, startIndex + deltaIndex, '/overlays/start/timestamp'),
64
- value: normalizePriceValue(before.start.value + deltaValue, pricePrecision, '/overlays/start/value'),
65
- };
66
- candidate.end = {
67
- timestamp: requireTimestamp(timestamps, endIndex + deltaIndex, '/overlays/end/timestamp'),
68
- value: normalizePriceValue(before.end.value + deltaValue, pricePrecision, '/overlays/end/value'),
69
- };
70
- return candidate;
71
176
  }