@baron1996/klinecharts-adapter 0.2.3 → 0.4.0

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.
Files changed (47) hide show
  1. package/dist/adapter.d.ts +27 -2
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/adapter.js +638 -26
  4. package/dist/conversion/chart-options.d.ts +3 -1
  5. package/dist/conversion/chart-options.d.ts.map +1 -1
  6. package/dist/conversion/chart-options.js +71 -0
  7. package/dist/conversion/overlays.d.ts +2 -1
  8. package/dist/conversion/overlays.d.ts.map +1 -1
  9. package/dist/conversion/overlays.js +1 -1
  10. package/dist/conversion/price.d.ts.map +1 -1
  11. package/dist/conversion/price.js +10 -39
  12. package/dist/drawing/engine-port.d.ts +71 -0
  13. package/dist/drawing/engine-port.d.ts.map +1 -0
  14. package/dist/drawing/engine-port.js +1 -0
  15. package/dist/drawing/interaction-normalization.d.ts +18 -0
  16. package/dist/drawing/interaction-normalization.d.ts.map +1 -0
  17. package/dist/drawing/interaction-normalization.js +61 -0
  18. package/dist/drawing/kline-projection-policy.d.ts +8 -0
  19. package/dist/drawing/kline-projection-policy.d.ts.map +1 -0
  20. package/dist/drawing/kline-projection-policy.js +69 -0
  21. package/dist/drawing/overlay-conversion.d.ts +9 -0
  22. package/dist/drawing/overlay-conversion.d.ts.map +1 -0
  23. package/dist/drawing/overlay-conversion.js +245 -0
  24. package/dist/drawing/projection-policy.d.ts +34 -0
  25. package/dist/drawing/projection-policy.d.ts.map +1 -0
  26. package/dist/drawing/projection-policy.js +10 -0
  27. package/dist/drawing/time-series-projection-policy.d.ts +6 -0
  28. package/dist/drawing/time-series-projection-policy.d.ts.map +1 -0
  29. package/dist/drawing/time-series-projection-policy.js +28 -0
  30. package/dist/extensions/price-measurement.d.ts +1 -1
  31. package/dist/extensions/price-measurement.d.ts.map +1 -1
  32. package/dist/extensions/price-measurement.js +8 -2
  33. package/dist/index.d.ts +8 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +8 -0
  36. package/dist/main-series-presentation.d.ts +35 -0
  37. package/dist/main-series-presentation.d.ts.map +1 -0
  38. package/dist/main-series-presentation.js +52 -0
  39. package/dist/time-series/adapter.d.ts +41 -0
  40. package/dist/time-series/adapter.d.ts.map +1 -0
  41. package/dist/time-series/adapter.js +1189 -0
  42. package/dist/time-series/indicator.d.ts +15 -0
  43. package/dist/time-series/indicator.d.ts.map +1 -0
  44. package/dist/time-series/indicator.js +56 -0
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +2 -2
@@ -1,5 +1,7 @@
1
- import type { ChartConfig } from '@baron1996/kline-scene-schema';
1
+ import type { ChartConfig, TimeSeriesChartConfig } from '@baron1996/kline-scene-schema';
2
2
  import type { Options } from 'klinecharts';
3
3
  /** 将纯数据 ChartConfig 转换为受控的 KLineCharts 初始化选项。 */
4
4
  export declare function toKLineChartsOptions(chart: ChartConfig): Options;
5
+ /** 将 TimeSeriesChartConfig 转换为隐藏 Candle 的受控初始化选项。 */
6
+ export declare function toKLineChartsTimeSeriesOptions(chart: TimeSeriesChartConfig): Options;
5
7
  //# sourceMappingURL=chart-options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-options.d.ts","sourceRoot":"","sources":["../../src/conversion/chart-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAGX,OAAO,EAEP,MAAM,aAAa,CAAC;AAmGrB,iDAAiD;AACjD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAiChE"}
1
+ {"version":3,"file":"chart-options.d.ts","sourceRoot":"","sources":["../../src/conversion/chart-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,WAAW,EACX,qBAAqB,EACrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAGX,OAAO,EAEP,MAAM,aAAa,CAAC;AA+IrB,iDAAiD;AACjD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAiChE;AAED,qDAAqD;AACrD,wBAAgB,8BAA8B,CAC7C,KAAK,EAAE,qBAAqB,GAC1B,OAAO,CA+BT"}
@@ -77,7 +77,13 @@ function chartStyles(chart) {
77
77
  noChangeWickColor: chart.candle.noChangeWickColor,
78
78
  },
79
79
  area: {
80
+ value: 'close',
81
+ lineColor: 'rgba(41, 98, 255, 1)',
82
+ lineSize: 2,
83
+ backgroundColor: 'rgba(0, 0, 0, 0)',
84
+ smooth: false,
80
85
  point: {
86
+ show: false,
81
87
  animation: false,
82
88
  },
83
89
  },
@@ -86,6 +92,41 @@ function chartStyles(chart) {
86
92
  yAxis: { tickText: text },
87
93
  };
88
94
  }
95
+ function timeSeriesChartStyles(chart) {
96
+ const text = {
97
+ color: chart.layout.textColor,
98
+ size: chart.layout.fontSize,
99
+ family: chart.layout.fontFamily,
100
+ };
101
+ return {
102
+ grid: {
103
+ horizontal: { show: true, color: chart.grid.horizontalColor },
104
+ vertical: { show: true, color: chart.grid.verticalColor },
105
+ },
106
+ candle: {
107
+ type: 'area',
108
+ area: {
109
+ lineSize: 0,
110
+ lineColor: 'rgba(0, 0, 0, 0)',
111
+ backgroundColor: 'rgba(0, 0, 0, 0)',
112
+ point: { show: false, animation: false },
113
+ },
114
+ priceMark: {
115
+ show: false,
116
+ high: { show: false },
117
+ low: { show: false },
118
+ last: { show: false },
119
+ },
120
+ tooltip: { showRule: 'none' },
121
+ },
122
+ indicator: {
123
+ lastValueMark: { show: false },
124
+ tooltip: { showRule: 'none' },
125
+ },
126
+ xAxis: { tickText: text },
127
+ yAxis: { tickText: text },
128
+ };
129
+ }
89
130
  /** 将纯数据 ChartConfig 转换为受控的 KLineCharts 初始化选项。 */
90
131
  export function toKLineChartsOptions(chart) {
91
132
  return {
@@ -121,3 +162,33 @@ export function toKLineChartsOptions(chart) {
121
162
  },
122
163
  };
123
164
  }
165
+ /** 将 TimeSeriesChartConfig 转换为隐藏 Candle 的受控初始化选项。 */
166
+ export function toKLineChartsTimeSeriesOptions(chart) {
167
+ return {
168
+ locale: chart.locale,
169
+ timezone: chart.timezone,
170
+ styles: timeSeriesChartStyles(chart),
171
+ formatter: {
172
+ formatDate: (params) => formatDate(params, chart.dateFormat),
173
+ formatBigNumber: (value) => formatLargeNumber(value, chart.largeNumberFormat),
174
+ },
175
+ thousandsSeparator: { sign: chart.thousandsSeparator },
176
+ decimalFold: {
177
+ threshold: chart.decimalFold.threshold,
178
+ format: chart.decimalFold.enabled
179
+ ? (value) => {
180
+ const source = String(value);
181
+ const expression = new RegExp(`\\.0{${chart.decimalFold.threshold},}[1-9][0-9]*$`);
182
+ if (!expression.test(source)) {
183
+ return source;
184
+ }
185
+ const [integer, decimal = ''] = source.split('.');
186
+ const zeroCount = decimal.match(/^0*/)?.[0].length ?? 0;
187
+ return `${integer}.0{${zeroCount}}${decimal.slice(zeroCount)}`;
188
+ }
189
+ : (value) => String(value),
190
+ },
191
+ zoomAnchor: chart.zoomAnchor === 'right' ? 'last_bar' : 'cursor',
192
+ hotkey: { enabled: false, exclude: [] },
193
+ };
194
+ }
@@ -1,5 +1,5 @@
1
1
  import type { ChartScene, SceneOverlay } from '@baron1996/kline-scene-schema';
2
- import type { Overlay, OverlayCreate } from 'klinecharts';
2
+ import type { DeepPartial, Overlay, OverlayCreate, OverlayStyle } from 'klinecharts';
3
3
  import type { EngineIdMap } from './id-map.js';
4
4
  export interface OverlaySourceSnapshot {
5
5
  readonly id: string;
@@ -25,6 +25,7 @@ export interface EngineOverlayCallbacks {
25
25
  readonly onSelected?: NonNullable<OverlayCreate['onSelected']>;
26
26
  readonly onDeselected?: NonNullable<OverlayCreate['onDeselected']>;
27
27
  }
28
+ export declare function toOverlayStyles(styles: SceneOverlay['styles']): DeepPartial<OverlayStyle>;
28
29
  export declare function toEngineOverlay(overlay: SceneOverlay, idMap: EngineIdMap, path: string, callbacks?: EngineOverlayCallbacks): OverlayCreate;
29
30
  /** 创建尚无几何点的交互式 Overlay,不把临时状态写入 Scene。 */
30
31
  export declare function toEngineOverlayDrawing(source: OverlayDrawingSource, idMap: EngineIdMap, callbacks: EngineOverlayCallbacks): OverlayCreate;
@@ -1 +1 @@
1
- {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/conversion/overlays.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,YAAY,EACZ,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAEX,OAAO,EACP,aAAa,EAGb,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC/E,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC;CACnE;AAoGD,wBAAgB,eAAe,CAC9B,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,sBAA2B,GACpC,aAAa,CAwBf;AAED,0CAA0C;AAC1C,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,sBAAsB,GAC/B,aAAa,CAsBf;AAiED,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,GACpB,YAAY,CAkHd;AAED,qBAAqB;AACrB,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE;IAAE,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAAE,EACpF,KAAK,EAAE,WAAW,EAClB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,sBAAsB,GAC3D,IAAI,CAiBN"}
1
+ {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/conversion/overlays.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,YAAY,EACZ,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EACX,WAAW,EACX,OAAO,EACP,aAAa,EACb,YAAY,EAEZ,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC/E,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC;CACnE;AAYD,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,CAkCzF;AAsDD,wBAAgB,eAAe,CAC9B,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,sBAA2B,GACpC,aAAa,CAwBf;AAED,0CAA0C;AAC1C,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,sBAAsB,GAC/B,aAAa,CAsBf;AAiED,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,GACpB,YAAY,CAkHd;AAED,qBAAqB;AACrB,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE;IAAE,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAAE,EACpF,KAAK,EAAE,WAAW,EAClB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,sBAAsB,GAC3D,IAAI,CAiBN"}
@@ -11,7 +11,7 @@ function toLineStyle(style) {
11
11
  smooth: false,
12
12
  };
13
13
  }
14
- function toOverlayStyles(styles) {
14
+ export function toOverlayStyles(styles) {
15
15
  const borderStyle = styles.line.style === 'solid' ? 'solid' : 'dashed';
16
16
  const borderDashedValue = styles.line.style === 'dotted' ? [1, 2] : [4, 4];
17
17
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../src/conversion/price.ts"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACV,MAAM,CAkCR"}
1
+ {"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../../src/conversion/price.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACV,MAAM,CAeR"}
@@ -1,48 +1,19 @@
1
1
  import { SceneError } from '@baron1996/kline-scene-schema';
2
- function toDecimalParts(value) {
3
- const [coefficient = '', exponentText] = value.toString().toLowerCase().split('e');
4
- const [integer = '', fraction = ''] = coefficient.split('.');
5
- return {
6
- digits: BigInt(`${integer}${fraction}`),
7
- exponent: Number(exponentText ?? 0) - fraction.length,
8
- };
9
- }
10
- function toDecimalNumber(value, precision, negative) {
11
- const digits = value.toString().padStart(precision + 1, '0');
12
- const unsigned = precision === 0
13
- ? digits
14
- : `${digits.slice(0, -precision)}.${digits.slice(-precision)}`;
15
- return Number(`${negative ? '-' : ''}${unsigned}`);
16
- }
2
+ import { normalizeDecimalValue } from '@baron1996/kline-scene-schema';
17
3
  /**
18
4
  * 把引擎价格按 Scene 标的精度做十进制舍入。
19
5
  * 舍入规则为最接近,恰好半值时远离零;任何负零统一输出正零。
20
6
  */
21
7
  export function normalizePriceValue(value, pricePrecision, path) {
22
- if (!Number.isFinite(value)) {
23
- throw new SceneError('EXPORT_INVALID', path, 'KLineCharts returned a non-finite price value.');
24
- }
25
- if (!Number.isInteger(pricePrecision) ||
26
- pricePrecision < 0 ||
27
- pricePrecision > 16) {
28
- throw new SceneError('EXPORT_INVALID', '/symbol/pricePrecision', 'Scene pricePrecision must be an integer from 0 through 16.');
29
- }
30
- const negative = value < 0;
31
- const { digits, exponent } = toDecimalParts(Math.abs(value));
32
- const scaledExponent = exponent + pricePrecision;
33
- let rounded;
34
- if (scaledExponent >= 0) {
35
- rounded = digits * (10n ** BigInt(scaledExponent));
36
- }
37
- else {
38
- const divisor = 10n ** BigInt(-scaledExponent);
39
- const quotient = digits / divisor;
40
- const remainder = digits % divisor;
41
- rounded = quotient + (remainder * 2n >= divisor ? 1n : 0n);
8
+ try {
9
+ return normalizeDecimalValue(value, pricePrecision);
42
10
  }
43
- const normalized = toDecimalNumber(rounded, pricePrecision, negative);
44
- if (!Number.isFinite(normalized)) {
45
- throw new SceneError('EXPORT_INVALID', path, 'Normalized price value is not finite.');
11
+ catch (error) {
12
+ if (error instanceof RangeError) {
13
+ throw new SceneError('EXPORT_INVALID', Number.isInteger(pricePrecision) && pricePrecision >= 0 && pricePrecision <= 16
14
+ ? path
15
+ : '/symbol/pricePrecision', error.message);
16
+ }
17
+ throw error;
46
18
  }
47
- return Object.is(normalized, -0) ? 0 : normalized;
48
19
  }
@@ -0,0 +1,71 @@
1
+ import type { Drawing } from '@baron1996/kline-scene-schema';
2
+ export interface EngineDrawingTarget {
3
+ readonly paneRole: string;
4
+ readonly yAxisRole: 'primary';
5
+ }
6
+ /** 引擎无关的 Drawing 快照;不出现 Chart、Overlay 实例或引擎内部 ID。 */
7
+ export interface EngineDrawingSnapshot {
8
+ readonly id: string;
9
+ readonly type: Drawing['type'];
10
+ readonly target: EngineDrawingTarget;
11
+ readonly geometry: Drawing['geometry'];
12
+ readonly styles: Drawing['styles'];
13
+ readonly text?: string;
14
+ readonly locked: boolean;
15
+ readonly visible: boolean;
16
+ readonly zLevel: number;
17
+ readonly mode: Drawing['mode'];
18
+ }
19
+ export interface EngineDrawingStartRequest {
20
+ readonly id: string;
21
+ readonly type: Drawing['type'];
22
+ readonly target: EngineDrawingTarget;
23
+ readonly styles: Drawing['styles'];
24
+ readonly text?: string;
25
+ }
26
+ export type EngineDrawingEventType = 'created' | 'updated' | 'removed' | 'selected' | 'deselected' | 'edit-candidate';
27
+ export interface EngineDrawingEvent {
28
+ readonly type: EngineDrawingEventType;
29
+ readonly id: string;
30
+ readonly drawing?: EngineDrawingSnapshot;
31
+ readonly editDimensions?: {
32
+ readonly horizontal: boolean;
33
+ readonly vertical: boolean;
34
+ };
35
+ }
36
+ export interface EnginePointProjection {
37
+ readonly x?: number;
38
+ readonly y?: number;
39
+ readonly timestamp?: number;
40
+ readonly value?: number;
41
+ }
42
+ export interface EnginePixelCoordinate {
43
+ readonly x: number;
44
+ readonly y: number;
45
+ }
46
+ /**
47
+ * 两个 Scene Adapter 共同实现的公共 Drawing 引擎端口。
48
+ * 所有 DTO 都是纯数据;端口调用方不能取得 Chart/Overlay 实例或引擎内部 ID。
49
+ */
50
+ export interface DrawingEnginePort {
51
+ readonly sceneKind: 'chart' | 'time-series';
52
+ restoreDrawings(drawings: readonly EngineDrawingSnapshot[]): void;
53
+ startDrawing(request: EngineDrawingStartRequest): string;
54
+ listDrawings(): readonly EngineDrawingSnapshot[];
55
+ getDrawing(id: string): EngineDrawingSnapshot | undefined;
56
+ updateDrawingStyles(id: string, styles: Drawing['styles']): EngineDrawingSnapshot;
57
+ updateDrawingText(id: string, text: string): EngineDrawingSnapshot;
58
+ restoreDrawing(snapshot: EngineDrawingSnapshot): void;
59
+ removeDrawing(id: string): boolean;
60
+ selectDrawing(id: string | null): void;
61
+ hitTestDrawing(point: EnginePixelCoordinate): string | null;
62
+ projectToPixel(anchor: {
63
+ readonly timestamp?: number;
64
+ readonly value?: number;
65
+ }, paneRole: string): EnginePointProjection;
66
+ unprojectFromPixel(point: EnginePixelCoordinate, paneRole: string): EnginePointProjection;
67
+ setMutationsEnabled(enabled: boolean): void;
68
+ subscribeDrawingEvents(listener: (event: EngineDrawingEvent) => void): () => void;
69
+ dispose(): void;
70
+ }
71
+ //# sourceMappingURL=engine-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-port.d.ts","sourceRoot":"","sources":["../../src/drawing/engine-port.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { EngineDrawingEvent, EngineDrawingSnapshot } from './engine-port.js';
2
+ export interface InteractionDimensions {
3
+ readonly horizontal: boolean;
4
+ readonly vertical: boolean;
5
+ }
6
+ /** 归一化后的引擎交互事件;编辑维度由 Adapter 拖动会话显式提供,不靠数值猜测。 */
7
+ export interface NormalizedDrawingEvent {
8
+ readonly type: EngineDrawingEvent['type'];
9
+ readonly id: string;
10
+ readonly snapshot: EngineDrawingSnapshot;
11
+ readonly dimensions: InteractionDimensions;
12
+ }
13
+ export declare function normalizeCreatedEvent(snapshot: EngineDrawingSnapshot): NormalizedDrawingEvent;
14
+ export declare function normalizeUpdatedEvent(snapshot: EngineDrawingSnapshot, dimensions: InteractionDimensions): NormalizedDrawingEvent;
15
+ export declare function normalizeEditCandidateEvent(snapshot: EngineDrawingSnapshot, dimensions: InteractionDimensions): NormalizedDrawingEvent;
16
+ export declare function normalizeRemovedEvent(snapshot: EngineDrawingSnapshot): NormalizedDrawingEvent;
17
+ export declare function normalizeSelectionEvent(id: string, type: 'selected' | 'deselected'): NormalizedDrawingEvent;
18
+ //# sourceMappingURL=interaction-normalization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-normalization.d.ts","sourceRoot":"","sources":["../../src/drawing/interaction-normalization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAClB,qBAAqB,EACrB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC3B;AAED,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;CAC3C;AAED,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,qBAAqB,GAC7B,sBAAsB,CAOxB;AAED,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,qBAAqB,EAC/B,UAAU,EAAE,qBAAqB,GAC/B,sBAAsB,CAOxB;AAED,wBAAgB,2BAA2B,CAC1C,QAAQ,EAAE,qBAAqB,EAC/B,UAAU,EAAE,qBAAqB,GAC/B,sBAAsB,CAOxB;AAED,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,qBAAqB,GAC7B,sBAAsB,CAOxB;AAED,wBAAgB,uBAAuB,CACtC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,UAAU,GAAG,YAAY,GAC7B,sBAAsB,CA4BxB"}
@@ -0,0 +1,61 @@
1
+ export function normalizeCreatedEvent(snapshot) {
2
+ return {
3
+ type: 'created',
4
+ id: snapshot.id,
5
+ snapshot,
6
+ dimensions: { horizontal: true, vertical: true },
7
+ };
8
+ }
9
+ export function normalizeUpdatedEvent(snapshot, dimensions) {
10
+ return {
11
+ type: 'updated',
12
+ id: snapshot.id,
13
+ snapshot,
14
+ dimensions,
15
+ };
16
+ }
17
+ export function normalizeEditCandidateEvent(snapshot, dimensions) {
18
+ return {
19
+ type: 'edit-candidate',
20
+ id: snapshot.id,
21
+ snapshot,
22
+ dimensions,
23
+ };
24
+ }
25
+ export function normalizeRemovedEvent(snapshot) {
26
+ return {
27
+ type: 'removed',
28
+ id: snapshot.id,
29
+ snapshot,
30
+ dimensions: { horizontal: false, vertical: false },
31
+ };
32
+ }
33
+ export function normalizeSelectionEvent(id, type) {
34
+ return {
35
+ type,
36
+ id,
37
+ snapshot: {
38
+ id,
39
+ type: 'horizontalStraightLine',
40
+ target: { paneRole: '', yAxisRole: 'primary' },
41
+ geometry: { value: 0 },
42
+ styles: {
43
+ line: { color: 'rgba(41, 98, 255, 1)', size: 1, style: 'solid' },
44
+ fill: { color: 'rgba(41, 98, 255, 0.15)' },
45
+ text: {
46
+ color: 'rgba(255, 255, 255, 1)',
47
+ size: 12,
48
+ family: 'Baron Sans',
49
+ weight: 'normal',
50
+ backgroundColor: 'rgba(41, 98, 255, 1)',
51
+ borderColor: 'rgba(41, 98, 255, 1)',
52
+ },
53
+ },
54
+ locked: false,
55
+ visible: true,
56
+ zLevel: 0,
57
+ mode: 'normal',
58
+ },
59
+ dimensions: { horizontal: false, vertical: false },
60
+ };
61
+ }
@@ -0,0 +1,8 @@
1
+ import type { ChartScene, Drawing, ValueAxis } from '@baron1996/kline-scene-schema';
2
+ import { type DrawingProjectionPolicy, type ResolveAxisBindingInput, type ResolvedAxisBinding } from './projection-policy.js';
3
+ /** K 线场景薄绑定策略;只解析 candle/indicator 与 primary 轴。 */
4
+ export declare class KLineDrawingProjectionPolicy implements DrawingProjectionPolicy {
5
+ resolveAxisBinding(input: ResolveAxisBindingInput): ResolvedAxisBinding;
6
+ }
7
+ export type { ChartScene, Drawing, ValueAxis };
8
+ //# sourceMappingURL=kline-projection-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kline-projection-policy.d.ts","sourceRoot":"","sources":["../../src/drawing/kline-projection-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAEpF,OAAO,EAEN,KAAK,uBAAuB,EAE5B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,MAAM,wBAAwB,CAAC;AAwBhC,mDAAmD;AACnD,qBAAa,4BAA6B,YAAW,uBAAuB;IACpE,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,mBAAmB;CAgG9E;AAED,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { DrawingProjectionError, } from './projection-policy.js';
2
+ function candlePrimaryScale(scene) {
3
+ const pane = scene.panes.find((candidate) => candidate.kind === 'candle');
4
+ return pane?.yAxes.find((axis) => axis.role === 'primary')?.scale ?? 'linear';
5
+ }
6
+ function requirePrimaryAxis(scene, paneId, path) {
7
+ const pane = scene.panes.find((candidate) => candidate.id === paneId);
8
+ const primary = pane?.yAxes.find((axis) => axis.role === 'primary');
9
+ if (primary === undefined) {
10
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target`, 'KLine indicator target must bind the primary axis of its owning Pane.');
11
+ }
12
+ return primary.id;
13
+ }
14
+ /** K 线场景薄绑定策略;只解析 candle/indicator 与 primary 轴。 */
15
+ export class KLineDrawingProjectionPolicy {
16
+ resolveAxisBinding(input) {
17
+ const { scene, drawing, valueAxes, path } = input;
18
+ if (scene.kind !== 'chart') {
19
+ throw new DrawingProjectionError('DRAWING_PROJECTION_INVALID', path, 'KLineDrawingProjectionPolicy requires a chart Scene.');
20
+ }
21
+ const target = drawing.target;
22
+ if (target.yAxisRole !== 'primary') {
23
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target/yAxisRole`, 'v1 Drawing targets only allow the primary y-axis role.');
24
+ }
25
+ if (target.paneRole === 'candle') {
26
+ const axis = valueAxes.find((candidate) => candidate.paneRole === 'candle' &&
27
+ candidate.yAxisRole === 'primary');
28
+ if (axis === undefined ||
29
+ axis.valuePrecision !== scene.document.symbol.pricePrecision) {
30
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target`, 'Candle target precision must equal symbol.pricePrecision.');
31
+ }
32
+ return {
33
+ paneRole: 'candle',
34
+ yAxisRole: 'primary',
35
+ valuePrecision: axis.valuePrecision,
36
+ scale: candlePrimaryScale(scene.document),
37
+ };
38
+ }
39
+ if (target.paneRole.startsWith('indicator:')) {
40
+ const indicatorId = target.paneRole.slice('indicator:'.length);
41
+ const matches = scene.document.panes
42
+ .flatMap((pane) => pane.indicators)
43
+ .filter((indicator) => indicator.id === indicatorId);
44
+ if (matches.length !== 1) {
45
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target`, `Indicator target must resolve to exactly one SceneIndicator: ${indicatorId}.`);
46
+ }
47
+ const indicator = matches[0];
48
+ const primaryAxisId = requirePrimaryAxis(scene.document, indicator.paneId, path);
49
+ if (indicator.yAxisId !== primaryAxisId) {
50
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target`, 'Indicator target must bind the primary axis of its owning Pane.');
51
+ }
52
+ const axis = valueAxes.find((candidate) => candidate.paneRole === target.paneRole &&
53
+ candidate.yAxisRole === 'primary');
54
+ if (axis === undefined || axis.valuePrecision !== indicator.precision) {
55
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target`, 'Indicator target precision must equal the indicator precision.');
56
+ }
57
+ const pane = scene.document.panes.find((candidate) => candidate.id === indicator.paneId);
58
+ const scale = pane?.yAxes.find((candidate) => candidate.role === 'primary')?.scale
59
+ ?? 'linear';
60
+ return {
61
+ paneRole: target.paneRole,
62
+ yAxisRole: 'primary',
63
+ valuePrecision: axis.valuePrecision,
64
+ scale,
65
+ };
66
+ }
67
+ throw new DrawingProjectionError('DRAWING_TARGET_INVALID', `${path}/target/paneRole`, `KLine Scene cannot interpret pane role: ${target.paneRole}.`);
68
+ }
69
+ }
@@ -0,0 +1,9 @@
1
+ import type { Drawing, SceneOverlay } from '@baron1996/kline-scene-schema';
2
+ /**
3
+ * Drawing 业务几何 ↔ 旧 SceneOverlay 兼容几何的纯数据映射。
4
+ * 不写回 dataIndex、paneId、yAxisId 或任何引擎内部 ID。
5
+ */
6
+ export declare function drawingToSceneOverlay(drawing: Drawing, paneId: string): SceneOverlay;
7
+ /** 用引擎归一化后的 SceneOverlay 几何重建 Drawing;granularity 从源 Drawing 恢复。 */
8
+ export declare function sceneOverlayToDrawing(overlay: SceneOverlay, source: Drawing): Drawing;
9
+ //# sourceMappingURL=overlay-conversion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-conversion.d.ts","sourceRoot":"","sources":["../../src/drawing/overlay-conversion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,OAAO,EAEP,YAAY,EACZ,MAAM,+BAA+B,CAAC;AAEvC;;;GAGG;AAEH,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GACZ,YAAY,CA6Fd;AAcD,oEAAoE;AACpE,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,OAAO,GACb,OAAO,CA6GT"}