@363045841yyt/klinechart 0.1.1 → 0.1.2

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 (43) hide show
  1. package/README.md +286 -245
  2. package/dist/App.vue.d.ts +1 -1
  3. package/dist/components/KLineChart.vue.d.ts +19 -6
  4. package/dist/components/KLineTooltip.vue.d.ts +15 -0
  5. package/dist/composables/useKLineInteraction.d.ts +50 -0
  6. package/dist/composables/useKLineRenderer.d.ts +49 -0
  7. package/dist/core/chart.d.ts +145 -0
  8. package/dist/core/controller/interaction.d.ts +50 -0
  9. package/dist/core/layout/pane.d.ts +72 -0
  10. package/dist/core/renderers/candle.d.ts +6 -0
  11. package/dist/core/renderers/crosshair.d.ts +13 -0
  12. package/dist/core/renderers/crosshairLabels.d.ts +17 -0
  13. package/dist/core/renderers/extremaMarkers.d.ts +8 -0
  14. package/dist/core/renderers/grid.d.ts +6 -0
  15. package/dist/core/renderers/gridLines.d.ts +7 -0
  16. package/dist/core/renderers/lastPrice.d.ts +5 -0
  17. package/dist/core/renderers/ma.d.ts +11 -0
  18. package/dist/core/renderers/maLegend.d.ts +9 -0
  19. package/dist/core/renderers/paneBorder.d.ts +14 -0
  20. package/dist/core/renderers/paneSeparator.d.ts +10 -0
  21. package/dist/core/renderers/paneTitle.d.ts +6 -0
  22. package/dist/core/renderers/timeAxis.d.ts +15 -0
  23. package/dist/core/renderers/yAxis.d.ts +11 -0
  24. package/dist/core/scale/price.d.ts +11 -0
  25. package/dist/core/scale/priceScale.d.ts +18 -0
  26. package/dist/core/viewport/viewport.d.ts +31 -0
  27. package/dist/index.cjs +1 -1
  28. package/dist/index.js +1036 -121
  29. package/dist/klinechart.css +1 -1
  30. package/dist/types/price.d.ts +14 -0
  31. package/dist/utils/dateFormat.d.ts +68 -0
  32. package/dist/utils/kLineDraw/MA.d.ts +8 -0
  33. package/dist/utils/kLineDraw/axis.d.ts +113 -0
  34. package/dist/utils/kLineDraw/grid.d.ts +30 -0
  35. package/dist/utils/{draw → kLineDraw}/kLine.d.ts +6 -8
  36. package/dist/utils/kLineDraw/pixelAlign.d.ts +48 -0
  37. package/dist/utils/kline/format.d.ts +14 -0
  38. package/dist/utils/kline/ma.d.ts +2 -0
  39. package/dist/utils/kline/viewport.d.ts +10 -0
  40. package/dist/utils/logger.d.ts +1 -1
  41. package/dist/utils/priceToY.d.ts +6 -0
  42. package/package.json +57 -55
  43. package/dist/utils/draw/MA.d.ts +0 -5
@@ -0,0 +1,49 @@
1
+ import { Ref } from 'vue';
2
+ import { KLineData } from '../types/price';
3
+ import { PriceRange } from '../utils/kline/viewport';
4
+ export type MAFlags = {
5
+ ma5?: boolean;
6
+ ma10?: boolean;
7
+ ma20?: boolean;
8
+ };
9
+ export type CrosshairPos = {
10
+ x: number;
11
+ y: number;
12
+ } | null;
13
+ export type KLineOption = {
14
+ kWidth: number;
15
+ kGap: number;
16
+ yPaddingPx?: number;
17
+ };
18
+ export type KLineViewport = {
19
+ viewWidth: number;
20
+ viewHeight: number;
21
+ plotWidth: number;
22
+ plotHeight: number;
23
+ rightAxisWidth: number;
24
+ bottomAxisHeight: number;
25
+ scrollLeft: number;
26
+ start: number;
27
+ end: number;
28
+ priceRange: PriceRange;
29
+ dpr: number;
30
+ };
31
+ export declare function useKLineRenderer(args: {
32
+ plotCanvasRef: Ref<HTMLCanvasElement | null>;
33
+ yAxisCanvasRef: Ref<HTMLCanvasElement | null>;
34
+ xAxisCanvasRef: Ref<HTMLCanvasElement | null>;
35
+ canvasLayerRef: Ref<HTMLDivElement | null>;
36
+ containerRef: Ref<HTMLDivElement | null>;
37
+ getData: () => KLineData[];
38
+ getOption: () => KLineOption;
39
+ getShowMA: () => MAFlags;
40
+ rightAxisWidth: Ref<number>;
41
+ bottomAxisHeight: Ref<number>;
42
+ crosshairPos: Ref<CrosshairPos>;
43
+ crosshairIndex: Ref<number | null>;
44
+ }): {
45
+ scheduleRender: () => void;
46
+ render: () => void;
47
+ getLastViewport: () => KLineViewport | null;
48
+ destroy: () => void;
49
+ };
@@ -0,0 +1,145 @@
1
+ import { KLineData } from '../types/price';
2
+ import { Pane } from './layout/pane';
3
+ import { InteractionController } from './controller/interaction';
4
+ export type ChartDom = {
5
+ container: HTMLDivElement;
6
+ canvasLayer: HTMLDivElement;
7
+ plotCanvas: HTMLCanvasElement;
8
+ yAxisCanvas: HTMLCanvasElement;
9
+ xAxisCanvas: HTMLCanvasElement;
10
+ };
11
+ export type PaneSpec = {
12
+ id: string;
13
+ ratio: number;
14
+ };
15
+ export type ChartOptions = {
16
+ kWidth: number;
17
+ kGap: number;
18
+ yPaddingPx: number;
19
+ rightAxisWidth: number;
20
+ bottomAxisHeight: number;
21
+ minKWidth: number;
22
+ maxKWidth: number;
23
+ panes: PaneSpec[];
24
+ /** pane 之间的真实分隔空隙(逻辑像素) */
25
+ paneGap?: number;
26
+ };
27
+ export type Viewport = {
28
+ viewWidth: number;
29
+ viewHeight: number;
30
+ plotWidth: number;
31
+ plotHeight: number;
32
+ scrollLeft: number;
33
+ dpr: number;
34
+ };
35
+ export declare class Chart {
36
+ private dom;
37
+ private opt;
38
+ private data;
39
+ private raf;
40
+ private viewport;
41
+ private panes;
42
+ readonly interaction: InteractionController;
43
+ private onZoomChange?;
44
+ /**
45
+ * 注册缩放回调。
46
+ *
47
+ * 为什么需要它:
48
+ * - `zoomAt()` 会更新 core 内部的 `kWidth/kGap`,但项目的横向滚动范围来自 Vue 层 `.scroll-content` 的宽度。
49
+ * - Vue 需要先用新的 kWidth/kGap 重新计算内容宽度(触发 DOM 更新 scrollWidth),
50
+ * 再设置正确的 scrollLeft,否则会出现“放大后无法拖到最右侧”的问题。
51
+ *
52
+ * @param cb (newKWidth, newKGap, targetScrollLeft) => void
53
+ */
54
+ setOnZoomChange(cb: (kWidth: number, kGap: number, targetScrollLeft: number) => void): void;
55
+ /**
56
+ * 创建图表实例。
57
+ *
58
+ * @param dom 由 Vue 组件传入的 DOM 句柄(container/canvasLayer/三层 canvas)
59
+ * @param opt 初始配置(kWidth/kGap、轴尺寸、pane 配置等)
60
+ */
61
+ constructor(dom: ChartDom, opt: ChartOptions);
62
+ /** 获取所有 pane(包含布局信息与 renderers 列表) */
63
+ getPanes(): Pane[];
64
+ /**
65
+ * 设置某个 pane 的渲染器链(按顺序执行)。
66
+ *
67
+ * @param paneId pane 标识(例如 'main'/'sub')
68
+ * @param renderers 渲染器数组;会清空并替换原有列表(保持引用稳定)
69
+ */
70
+ setPaneRenderers(paneId: string, renderers: Pane['renderers']): void;
71
+ /** 获取 ChartDom(供 InteractionController 等使用) */
72
+ getDom(): ChartDom;
73
+ /** 获取当前 ChartOptions(注意:返回的是内部当前快照) */
74
+ getOption(): ChartOptions;
75
+ /**
76
+ * 更新配置并触发布局/重绘。
77
+ * - 更新 panes 时会重建 Pane 实例并重新布局。
78
+ */
79
+ updateOptions(partial: Partial<ChartOptions>): void;
80
+ /**
81
+ * 更新数据并请求重绘。
82
+ * @param data K 线数据数组(null/undefined 会被视为 [])
83
+ */
84
+ updateData(data: KLineData[]): void;
85
+ /** 获取当前数据源(给 renderers/interaction 使用) */
86
+ getData(): KLineData[];
87
+ /**
88
+ * 内容总宽度(用于外部 scroll-content 撑开 scrollWidth)
89
+ * 规则:kGap + n*(kWidth+kGap) + rightAxisWidth
90
+ */
91
+ getContentWidth(): number;
92
+ /**
93
+ * 容器尺寸变化时调用:
94
+ * - 重新计算 viewport(DPR/plotWidth/plotHeight)
95
+ * - 重新计算 pane 布局
96
+ * - 请求重绘
97
+ */
98
+ resize(): void;
99
+ /**
100
+ * 请求下一帧重绘(RAF 合并)。
101
+ * 多次调用只会触发一次 draw,避免频繁重绘。
102
+ */
103
+ scheduleDraw(): void;
104
+ /**
105
+ * 绘制一帧:
106
+ * 1) computeViewport(设置 canvas 尺寸)
107
+ * 2) 计算可视区 range(start/end)
108
+ * 3) 对每个 pane:更新 priceRange -> 执行 renderers(plotCanvas)-> 画 yAxis(yAxisCanvas)
109
+ * 4) 画 xAxis(xAxisCanvas)
110
+ * 5) 画 overlay(十字线、图例、边框等)
111
+ */
112
+ draw(): void;
113
+ /**
114
+ * 在给定 mouseX(相对 container 左侧)处做缩放。
115
+ *
116
+ * 设计目标:缩放后保持 mouseX 指向的“数据索引”尽量稳定(以该点为中心缩放)。
117
+ *
118
+ * @param mouseX 鼠标相对 container 的 x(逻辑像素)
119
+ * @param scrollLeft 当前 container.scrollLeft
120
+ * @param deltaY WheelEvent.deltaY(>0 缩小,<0 放大)
121
+ */
122
+ zoomAt(mouseX: number, scrollLeft: number, deltaY: number): void;
123
+ /**
124
+ * 销毁 chart:
125
+ * - 取消 RAF
126
+ * - 释放引用,避免内存泄漏
127
+ */
128
+ destroy(): void;
129
+ /** 根据 opt.panes 重建 Pane 实例列表 */
130
+ private initPanes;
131
+ /**
132
+ * 计算每个 pane 的布局(top/height)。
133
+ * - 按 ratio 分配高度
134
+ * - 支持 paneGap 形成真实留白
135
+ */
136
+ private layoutPanes;
137
+ /**
138
+ * 计算并应用 viewport:
139
+ * - 读取 container 尺寸
140
+ * - 计算 plot 区域尺寸(扣掉右轴/底轴)
141
+ * - 处理 DPR 以及最大像素限制(避免超大 canvas)
142
+ * - 设置 canvasLayer/三个 canvas 的 style 尺寸与实际像素尺寸
143
+ */
144
+ private computeViewport;
145
+ }
@@ -0,0 +1,50 @@
1
+ import { Chart } from '../chart';
2
+ /**
3
+ * 交互控制器:只依赖 Chart 公共 API,不依赖 Vue。
4
+ * 先落地:拖拽滚动 / wheel 缩放。
5
+ * hover/crosshair 后续按同样方式接入。
6
+ */
7
+ export declare class InteractionController {
8
+ private chart;
9
+ private isDragging;
10
+ private dragStartX;
11
+ private scrollStartX;
12
+ private isTouchSession;
13
+ crosshairPos: {
14
+ x: number;
15
+ y: number;
16
+ } | null;
17
+ crosshairIndex: number | null;
18
+ hoveredIndex: number | null;
19
+ activePaneId: string | null;
20
+ tooltipPos: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ tooltipSize: {
25
+ width: number;
26
+ height: number;
27
+ };
28
+ constructor(chart: Chart);
29
+ /**
30
+ * Pointer 事件:用于移动端/触屏设备。
31
+ * 设计目标:手指一接触屏幕(pointerdown)就立刻更新 crosshair。
32
+ */
33
+ onPointerDown(e: PointerEvent): void;
34
+ onPointerMove(e: PointerEvent): void;
35
+ onPointerUp(e: PointerEvent): void;
36
+ onPointerLeave(e: PointerEvent): void;
37
+ onMouseDown(e: MouseEvent): void;
38
+ onMouseMove(e: MouseEvent): void;
39
+ onMouseUp(): void;
40
+ onMouseLeave(): void;
41
+ onScroll(): void;
42
+ onWheel(e: WheelEvent): void;
43
+ setTooltipSize(size: {
44
+ width: number;
45
+ height: number;
46
+ }): void;
47
+ private clearHover;
48
+ private updateHover;
49
+ private updateHoverFromPoint;
50
+ }
@@ -0,0 +1,72 @@
1
+ import { KLineData } from '../../types/price';
2
+ import { PriceRange } from '../scale/price';
3
+ import { PriceScale } from '../scale/priceScale';
4
+ export type VisibleRange = {
5
+ start: number;
6
+ end: number;
7
+ };
8
+ /**
9
+ * Pane 级渲染器接口:在单个 pane 的坐标系中绘制内容。
10
+ *
11
+ * 约定:
12
+ * - 调用前 Chart 已经对 `ctx` 做了 `translate(0, pane.top)`,因此 y=0 对应 pane 顶部。
13
+ * - 如需随滚动的 world 坐标,需要 renderer 内部执行 `ctx.translate(-scrollLeft, 0)`。
14
+ */
15
+ export interface PaneRenderer {
16
+ draw(args: {
17
+ ctx: CanvasRenderingContext2D;
18
+ pane: Pane;
19
+ data: KLineData[];
20
+ range: VisibleRange;
21
+ scrollLeft: number;
22
+ kWidth: number;
23
+ kGap: number;
24
+ dpr: number;
25
+ }): void;
26
+ }
27
+ /**
28
+ * Pane:代表一个“窗口区域”(主图 / 副图)。
29
+ *
30
+ * 负责:
31
+ * - 记录自身布局(top/height)
32
+ * - 维护可视价格范围(priceRange)
33
+ * - 拥有独立的 Y 轴缩放器(PriceScale)
34
+ * - 保存一组渲染器(renderers),在 Chart.draw 中按顺序执行。
35
+ */
36
+ export declare class Pane {
37
+ readonly id: string;
38
+ top: number;
39
+ height: number;
40
+ /** 当前 pane 的可视价格范围(用于右侧轴、以及渲染器内部) */
41
+ priceRange: PriceRange;
42
+ /** pane 独立 Y 轴 */
43
+ readonly yAxis: PriceScale;
44
+ /** 该 pane 的渲染器列表 */
45
+ readonly renderers: PaneRenderer[];
46
+ /**
47
+ * @param id pane 标识符(例如 'main'、'sub'),用于在 Chart/Interaction 中识别 pane。
48
+ */
49
+ constructor(id: string);
50
+ /**
51
+ * 设置 pane 的垂直布局。
52
+ *
53
+ * @param top 相对 plotCanvas 顶部的偏移(逻辑像素)
54
+ * @param height pane 高度(逻辑像素)
55
+ */
56
+ setLayout(top: number, height: number): void;
57
+ /**
58
+ * 设置 Y 轴上下 padding(影响 priceToY 映射的上下留白)。
59
+ */
60
+ setPadding(top: number, bottom: number): void;
61
+ /**
62
+ * 注册一个 pane 级渲染器。
63
+ */
64
+ addRenderer(r: PaneRenderer): void;
65
+ /**
66
+ * 根据当前可见索引区间更新 priceRange,并同步到 yAxis。
67
+ *
68
+ * @param data 全量 K 线数据
69
+ * @param range 当前视口可见的索引范围(由 getVisibleRange 计算)
70
+ */
71
+ updateRange(data: KLineData[], range: VisibleRange): void;
72
+ }
@@ -0,0 +1,6 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ /**
3
+ * 最小 Candle 渲染器:依赖 pane.yAxis 做 price->y。
4
+ * 注意:这里暂时复用现有 pixelAlign 工具(后续可以一起迁到 core/draw)。
5
+ */
6
+ export declare const CandleRenderer: PaneRenderer;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 十字线渲染(屏幕坐标系):
3
+ * - ctx 处于 plotCanvas 的屏幕坐标(不带 translate(-scrollLeft,0))
4
+ * - x/y 是相对 plot 区域左上角的坐标(即 container 内坐标)
5
+ */
6
+ export declare function drawCrosshair(args: {
7
+ ctx: CanvasRenderingContext2D;
8
+ plotWidth: number;
9
+ plotHeight: number;
10
+ dpr: number;
11
+ x: number;
12
+ y: number;
13
+ }): void;
@@ -0,0 +1,17 @@
1
+ import { Pane } from '../layout/pane';
2
+ import { KLineData } from '../../types/price';
3
+ export declare function drawCrosshairPriceLabelForPane(args: {
4
+ ctx: CanvasRenderingContext2D;
5
+ pane: Pane;
6
+ axisWidth: number;
7
+ dpr: number;
8
+ crosshairY: number;
9
+ yPaddingPx: number;
10
+ }): void;
11
+ export declare function drawCrosshairTimeLabelGlobal(args: {
12
+ ctx: CanvasRenderingContext2D;
13
+ data: KLineData[];
14
+ dpr: number;
15
+ crosshairX: number;
16
+ index: number;
17
+ }): void;
@@ -0,0 +1,8 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ /**
3
+ * 可视区最高/最低价标注(仅绘制标注,不绘制蜡烛)。
4
+ * 说明:
5
+ * - 使用 pane.yAxis.priceToY 作为 Y 映射(与当前 pane 的 priceRange 一致)
6
+ * - world 坐标绘制(会 translate(-scrollLeft, 0))
7
+ */
8
+ export declare const ExtremaMarkersRenderer: PaneRenderer;
@@ -0,0 +1,6 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ /**
3
+ * 网格渲染:按 pane 的局部坐标绘制(ctx 已 translate 到 pane.top)
4
+ * 复用旧的 drawGridLayer(内部要求 ctx 已 translate(-scrollLeft,0))。
5
+ */
6
+ export declare const GridRenderer: PaneRenderer;
@@ -0,0 +1,7 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ /**
3
+ * 仅绘制网格线(不绘制任何文字刻度)。
4
+ * - 横向:按像素均分(保证永远铺满整个绘图区高度,不受 priceRange 影响)
5
+ * - 纵向:按月分割(与时间轴刻度保持同一规则,但不画文字)
6
+ */
7
+ export declare const GridLinesRenderer: PaneRenderer;
@@ -0,0 +1,5 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ /**
3
+ * 最新价虚线:画在 plotCanvas 的 world 坐标系(需 translate(-scrollLeft,0))
4
+ */
5
+ export declare const LastPriceLineRenderer: PaneRenderer;
@@ -0,0 +1,11 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ export type MAFlags = {
3
+ ma5?: boolean;
4
+ ma10?: boolean;
5
+ ma20?: boolean;
6
+ };
7
+ /**
8
+ * MA 渲染:复用现有 drawMA*Line(world 坐标绘制:需 translate(-scrollLeft,0))。
9
+ * 注意:drawMA*Line 内部使用 priceToY + priceRange,因此可直接用 pane.priceRange。
10
+ */
11
+ export declare function createMARenderer(showMA: MAFlags): PaneRenderer;
@@ -0,0 +1,9 @@
1
+ import { MAFlags } from './ma';
2
+ import { KLineData } from '../../types/price';
3
+ export declare function drawMALegend(args: {
4
+ ctx: CanvasRenderingContext2D;
5
+ data: KLineData[];
6
+ endIndex: number;
7
+ showMA: MAFlags;
8
+ dpr: number;
9
+ }): void;
@@ -0,0 +1,14 @@
1
+ export declare function drawPaneBorders(args: {
2
+ ctx: CanvasRenderingContext2D;
3
+ dpr: number;
4
+ width: number;
5
+ panes: Array<{
6
+ top: number;
7
+ height: number;
8
+ }>;
9
+ color?: string;
10
+ omitOuterTop?: boolean;
11
+ omitOuterRight?: boolean;
12
+ omitOuterBottom?: boolean;
13
+ omitOuterLeft?: boolean;
14
+ }): void;
@@ -0,0 +1,10 @@
1
+ export declare function drawPaneSeparators(args: {
2
+ ctx: CanvasRenderingContext2D;
3
+ dpr: number;
4
+ plotWidth: number;
5
+ panes: Array<{
6
+ top: number;
7
+ height: number;
8
+ }>;
9
+ color?: string;
10
+ }): void;
@@ -0,0 +1,6 @@
1
+ export declare function drawPaneTitle(args: {
2
+ ctx: CanvasRenderingContext2D;
3
+ dpr: number;
4
+ paneTop: number;
5
+ title: string;
6
+ }): void;
@@ -0,0 +1,15 @@
1
+ import { KLineData } from '../../types/price';
2
+ export declare function drawTimeAxisLayer(args: {
3
+ ctx: CanvasRenderingContext2D;
4
+ data: KLineData[];
5
+ scrollLeft: number;
6
+ kWidth: number;
7
+ kGap: number;
8
+ startIndex: number;
9
+ endIndex: number;
10
+ dpr: number;
11
+ crosshair?: {
12
+ x: number;
13
+ index: number;
14
+ } | null;
15
+ }): void;
@@ -0,0 +1,11 @@
1
+ import { PaneRenderer } from '../layout/pane';
2
+ /**
3
+ * 右侧轴渲染:每个 pane 各画一段。
4
+ * 说明:目前复用旧的 axis.ts(后续再迁 core 化)。
5
+ */
6
+ export declare function createYAxisRenderer(opts: {
7
+ axisX: number;
8
+ axisWidth: number;
9
+ yPaddingPx: number;
10
+ ticks?: number;
11
+ }): PaneRenderer;
@@ -0,0 +1,11 @@
1
+ export type PriceRange = {
2
+ maxPrice: number;
3
+ minPrice: number;
4
+ };
5
+ export declare function priceToY(price: number, maxPrice: number, minPrice: number, canvasHeight: number, paddingTop: number, paddingBottom: number): number;
6
+ /**
7
+ * 将逻辑像素 y 反算回价格
8
+ * - y 是相对于绘图区顶部的逻辑像素坐标(不含额外 translate)
9
+ * - paddingTop/paddingBottom 需与 priceToY 使用一致
10
+ */
11
+ export declare function yToPrice(y: number, maxPrice: number, minPrice: number, canvasHeight: number, paddingTop: number, paddingBottom: number): number;
@@ -0,0 +1,18 @@
1
+ import { PriceRange } from './price';
2
+ /**
3
+ * Pane 级别的价格坐标系(价格 -> pane 内 Y)
4
+ * - y=0 在 pane 顶部,y=height 在 pane 底部
5
+ */
6
+ export declare class PriceScale {
7
+ private range;
8
+ private height;
9
+ private paddingTop;
10
+ private paddingBottom;
11
+ setRange(r: PriceRange): void;
12
+ setHeight(h: number): void;
13
+ setPadding(top: number, bottom: number): void;
14
+ getRange(): PriceRange;
15
+ getPaddingTop(): number;
16
+ getPaddingBottom(): number;
17
+ priceToY(price: number): number;
18
+ }
@@ -0,0 +1,31 @@
1
+ import { KLineData } from '../../types/price';
2
+ import { PriceRange } from '../scale/price';
3
+ /**
4
+ * 计算当前视口可见的 K 线索引范围。
5
+ *
6
+ * - 基于 `scrollLeft` 与 `viewWidth` 推导可见的 worldX 区间。
7
+ * - 再用 `unit = kWidth + kGap` 映射到索引区间。
8
+ * - 会额外在左右各扩展 1 根(start-1/end+1),用于避免边缘裁剪带来的“断线/缺一根”观感。
9
+ *
10
+ * @param scrollLeft 容器当前横向滚动量(逻辑像素)
11
+ * @param viewWidth 绘图区域宽度(plotWidth,逻辑像素,不含右侧 yAxis)
12
+ * @param kWidth 单根 K 线宽度(逻辑像素)
13
+ * @param kGap K 线间距(逻辑像素)
14
+ * @param totalDataCount 数据总条数
15
+ */
16
+ export declare function getVisibleRange(scrollLeft: number, viewWidth: number, kWidth: number, kGap: number, totalDataCount: number): {
17
+ start: number;
18
+ end: number;
19
+ };
20
+ /**
21
+ * 计算指定索引区间内的价格范围(max/min)。
22
+ *
23
+ * 主要用途:
24
+ * - 为 pane 的 y 轴缩放与刻度提供 priceRange
25
+ * - 为渲染器(网格线、极值标注等)提供可视区参考范围
26
+ *
27
+ * 注意:
28
+ * - `endIndex` 为开区间(不包含)
29
+ * - 若区间内无有效数据,会返回兜底范围 `{ maxPrice: 100, minPrice: 0 }`
30
+ */
31
+ export declare function getVisiblePriceRange(data: KLineData[], startIndex: number, endIndex: number): PriceRange;
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`);function t(e){return e.open>e.close?`down`:e.open<e.close?`up`:`flat`}function n(e,t,n,r,i,a){let o=t-n||1,s=(e-n)/o;return i+Math.max(1,r-i-a)*(1-s)}var r={info:`background:#1677ff;color:#fff;border:1px solid #1677ff;`,success:`background:#389e0d;color:#fff;border:1px solid #389e0d;`,warn:`background:#d46b08;color:#fff;border:1px solid #d46b08;`,error:`background:#cf1322;color:#fff;border:1px solid #cf1322;`},i=`padding:4px 8px;font-weight:600;border-radius:6px;`,a=`padding:4px 10px;border:1px solid #d9d9d9;background:#fff;color:#111;border-radius:6px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;`;function o(e,t,n){console.log(`%c${t}%c`,`${i}${r[e]}`,a,n)}var s=`rgba(214, 10, 34, 1)`,c=`rgba(3, 123, 102, 1)`;function l(e,r,i,a,l=1){if(o(`info`,`kLineDraw`,r),r.length===0)return;let u=a,d=i.yPaddingPx??0,f=Math.max(0,Math.min(d,Math.floor(u/2)-1)),p=f,m=f,h=r.reduce((e,t)=>Math.max(e,t.high),-1/0),g=r.reduce((e,t)=>Math.min(e,t.low),1/0);e.lineWidth=1/l;let _=i.kGap;for(let a=0;a<r.length;a++){let o=r[a];if(!o)continue;let d=n(o.high,h,g,u,p,m),f=n(o.low,h,g,u,p,m),v=n(o.open,h,g,u,p,m),y=n(o.close,h,g,u,p,m),b=Math.min(v,y),x=Math.max(Math.abs(v-y),2/l),S=t(o)===`up`?s:c;e.fillStyle=S,e.fillRect(_,b,i.kWidth,x),e.strokeStyle=S,e.lineWidth=3/l;let C=_+i.kWidth/2;e.beginPath(),e.moveTo(C,d),e.lineTo(C,b),e.stroke(),e.beginPath(),e.moveTo(C,b+x),e.lineTo(C,f),e.stroke(),_+=i.kWidth+i.kGap}}function u(e,t){let n=[...e].sort((e,t)=>e.timestamp-t.timestamp),r=n.length;if(t<=0)throw Error(`x must be > 0`);if(r<t)return[];let i=0;for(let e=0;e<t;e++)i+=n[e].close;let a=Array(r-t+1);a[0]=i/t;for(let e=t;e<r;e++)i+=n[e].close-n[e-t].close,a[e-t+1]=i/t;return a}function d(e,t,r,i,a,o,s=1){if(t.length===0)return;let c=[...t].sort((e,t)=>e.timestamp-t.timestamp),l=u(c,a);if(l.length===0)return;let d=i,f=r.yPaddingPx??0,p=Math.max(0,Math.min(f,Math.floor(d/2)-1)),m=p,h=p,g=c.reduce((e,t)=>Math.max(e,t.high),-1/0),_=c.reduce((e,t)=>Math.min(e,t.low),1/0);if(!Number.isFinite(g)||!Number.isFinite(_)||g<=_)return;let v=Array(l.length);for(let e=0;e<l.length;e++)v[e]=n(l[e],g,_,d,m,h);e.strokeStyle=o,e.lineWidth=2/s,e.beginPath();let y=!1;for(let t=0;t<v.length;t++){let n=v[t];if(!Number.isFinite(n))continue;let i=t+(a-1),o=r.kGap+i*(r.kWidth+r.kGap)+r.kWidth/2;y?e.lineTo(o,n):(e.moveTo(o,n),y=!0)}y&&e.stroke()}function f(e,t,n,r,i=1){d(e,t,n,r,10,`rgba(190, 131, 12, 1)`,i)}function p(e,t,n,r,i=1){d(e,t,n,r,20,`rgba(69, 112, 249, 1)`,i)}function m(e,t,n,r,i=1){d(e,t,n,r,5,`rgba(251, 186, 62, 1)`,i)}var h=(0,e.defineComponent)({__name:`KLineChart`,props:{data:{},kWidth:{default:10},kGap:{default:2},yPaddingPx:{default:60},showMA:{default:()=>({ma5:!0,ma10:!0,ma20:!0})},autoScrollToRight:{type:Boolean,default:!0}},setup(t,{expose:n}){let r=t,i=(0,e.ref)(null),a=(0,e.ref)(null),o=null;function s(){return{kWidth:r.kWidth,kGap:r.kGap,yPaddingPx:r.yPaddingPx}}function c(){let e=i.value,t=a.value;if(!e||!t||!r.data||r.data.length===0)return;let n=e.getContext(`2d`);if(!n)return;let o=r.data,c=t.getBoundingClientRect(),u=Math.max(1,Math.round(c.width)),d=Math.max(1,Math.round(c.height)),h=window.devicePixelRatio||1,g=s(),_=o.length,v=Math.max(u,g.kGap+_*(g.kWidth+g.kGap));e.style.width=`${v}px`,e.style.height=`${d}px`,e.width=Math.round(v*h),e.height=Math.round(d*h);let y=t.scrollLeft;n.setTransform(1,0,0,1,0,0),n.scale(h,h),n.clearRect(0,0,v,d),n.translate(-y,0),l(n,o,g,d,h),r.showMA.ma5&&m(n,o,g,d,h),r.showMA.ma10&&f(n,o,g,d,h),r.showMA.ma20&&p(n,o,g,d,h)}function u(){o!==null&&cancelAnimationFrame(o),o=requestAnimationFrame(()=>{o=null,c()})}function d(){let e=a.value;e&&(e.scrollLeft=e.scrollWidth,u())}return n({scheduleRender:u,scrollToRight:d}),(0,e.onMounted)(()=>{window.addEventListener(`resize`,u,{passive:!0}),u()}),(0,e.onUnmounted)(()=>{window.removeEventListener(`resize`,u),o!==null&&cancelAnimationFrame(o)}),(0,e.watch)(()=>[r.data,r.kWidth,r.kGap,r.yPaddingPx,r.showMA],async()=>{r.autoScrollToRight?(await(0,e.nextTick)(),d()):u()},{deep:!0}),(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{class:`chart-container`,ref_key:`containerRef`,ref:a,onScrollPassive:u},[(0,e.createElementVNode)(`canvas`,{ref_key:`canvasRef`,ref:i,class:`chart-canvas`},null,512)],544))}}),g=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n},_=g(h,[[`__scopeId`,`data-v-7f0057f3`]]);const v=_,y={install(e){e.component(`KLineChart`,v)}};exports.KLineChart=v,exports.KMapPlugin=y;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`);function t(e){let t=new Intl.DateTimeFormat(`zh-CN`,{timeZone:`Asia/Shanghai`,year:`numeric`,month:`2-digit`,day:`2-digit`}).formatToParts(new Date(e)).reduce((e,t)=>(t.type!==`literal`&&(e[t.type]=t.value),e),{});return`${t.year}-${t.month}-${t.day}`}function n(e){let t=new Date(e),n=t.getFullYear(),r=t.getMonth()+1;return r===1?{text:String(n),isYear:!0}:{text:String(r).padStart(2,`0`),isYear:!1}}function r(e){let t=new Date(e);return`${t.getFullYear()}-${t.getMonth()}`}const i=t,a=t,o=`rgba(214, 10, 34, 1)`,s=`rgba(3, 123, 102, 1)`,c=`rgba(0, 0, 0, 0.78)`;function l(e){return e>0?`rgba(214, 10, 34, 1)`:e<0?`rgba(3, 123, 102, 1)`:c}function u(e,t=2){let n=Math.abs(e);return n>=1e8?`${(e/1e8).toFixed(t)}亿`:n>=1e4?`${(e/1e4).toFixed(t)}万`:`${Math.round(e)}`}function d(e,t=2){return`${e>0?`+`:``}${e.toFixed(t)}`}function f(e,t=2){return`${e.toFixed(t)}%`}function p(e,t=2){return`${e>0?`+`:``}${e.toFixed(t)}%`}function m(e,t){let n=t?.close??e.open;return l(e.open-n)}function h(e){return l(e.close-e.open)}function g(e){return typeof e.changePercent==`number`?l(e.changePercent):typeof e.changeAmount==`number`?l(e.changeAmount):c}var _={class:`kline-tooltip__title`},v={key:0},y={class:`kline-tooltip__grid`},b={class:`row`},x={class:`row`},S={class:`row`},C={class:`row`},w={key:0,class:`row`},T={key:1,class:`row`},E={key:2,class:`row`},D={key:3,class:`row`},O={key:4,class:`row`},k={key:5,class:`row`},A=(0,e.defineComponent)({__name:`KLineTooltip`,props:{k:{},index:{},data:{},pos:{},setEl:{type:Function}},setup(t){let n=t;function r(e){n.setEl?.(e)}let a=(0,e.computed)(()=>{let e=n.k;if(!e)return c;let t=n.index;return m(e,typeof t==`number`&&t>0?n.data[t-1]:void 0)}),o=(0,e.computed)(()=>{let e=n.k;return e?h(e):c}),s=(0,e.computed)(()=>{let e=n.k;return e?g(e):c});return(n,c)=>t.k?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{key:0,ref:r,class:`kline-tooltip`,style:(0,e.normalizeStyle)({left:`${t.pos.x}px`,top:`${t.pos.y}px`})},[(0,e.createElementVNode)(`div`,_,[t.k.stockCode?((0,e.openBlock)(),(0,e.createElementBlock)(`span`,v,(0,e.toDisplayString)(t.k.stockCode),1)):(0,e.createCommentVNode)(``,!0),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)((0,e.unref)(i)(t.k.timestamp)),1)]),(0,e.createElementVNode)(`div`,y,[(0,e.createElementVNode)(`div`,b,[c[0]||=(0,e.createElementVNode)(`span`,null,`开`,-1),(0,e.createElementVNode)(`span`,{style:(0,e.normalizeStyle)({color:a.value})},(0,e.toDisplayString)(t.k.open.toFixed(2)),5)]),(0,e.createElementVNode)(`div`,x,[c[1]||=(0,e.createElementVNode)(`span`,null,`高`,-1),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)(t.k.high.toFixed(2)),1)]),(0,e.createElementVNode)(`div`,S,[c[2]||=(0,e.createElementVNode)(`span`,null,`低`,-1),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)(t.k.low.toFixed(2)),1)]),(0,e.createElementVNode)(`div`,C,[c[3]||=(0,e.createElementVNode)(`span`,null,`收`,-1),(0,e.createElementVNode)(`span`,{style:(0,e.normalizeStyle)({color:o.value})},(0,e.toDisplayString)(t.k.close.toFixed(2)),5)]),typeof t.k.volume==`number`?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,w,[c[4]||=(0,e.createElementVNode)(`span`,null,`成交量`,-1),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)((0,e.unref)(u)(t.k.volume)),1)])):(0,e.createCommentVNode)(``,!0),typeof t.k.turnover==`number`?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,T,[c[5]||=(0,e.createElementVNode)(`span`,null,`成交额`,-1),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)((0,e.unref)(u)(t.k.turnover)),1)])):(0,e.createCommentVNode)(``,!0),typeof t.k.amplitude==`number`?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,E,[c[6]||=(0,e.createElementVNode)(`span`,null,`振幅`,-1),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)(t.k.amplitude),1)])):(0,e.createCommentVNode)(``,!0),typeof t.k.changePercent==`number`?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,D,[c[7]||=(0,e.createElementVNode)(`span`,null,`涨跌幅`,-1),(0,e.createElementVNode)(`span`,{style:(0,e.normalizeStyle)({color:s.value})},(0,e.toDisplayString)((0,e.unref)(p)(t.k.changePercent)),5)])):(0,e.createCommentVNode)(``,!0),typeof t.k.changeAmount==`number`?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,O,[c[8]||=(0,e.createElementVNode)(`span`,null,`涨跌额`,-1),(0,e.createElementVNode)(`span`,{style:(0,e.normalizeStyle)({color:s.value})},(0,e.toDisplayString)((0,e.unref)(d)(t.k.changeAmount)),5)])):(0,e.createCommentVNode)(``,!0),typeof t.k.turnoverRate==`number`?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,k,[c[9]||=(0,e.createElementVNode)(`span`,null,`换手率`,-1),(0,e.createElementVNode)(`span`,null,(0,e.toDisplayString)((0,e.unref)(f)(t.k.turnoverRate)),1)])):(0,e.createCommentVNode)(``,!0)])],4)):(0,e.createCommentVNode)(``,!0)}}),j=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n},M=j(A,[[`__scopeId`,`data-v-8d05acf2`]]);function N(e,t,n,r,i){let a=n+r;return{start:Math.max(0,Math.floor(e/a)-1),end:Math.min(i,Math.ceil((e+t)/a)+1)}}function P(e,t,n){let r=-1/0,i=1/0;for(let a=t;a<n&&a<e.length;a++){let t=e[a];t&&(t.high>r&&(r=t.high),t.low<i&&(i=t.low))}return!Number.isFinite(r)||!Number.isFinite(i)?{maxPrice:100,minPrice:0}:{maxPrice:r,minPrice:i}}var F=class{range={maxPrice:100,minPrice:0};height=1;paddingTop=0;paddingBottom=0;setRange(e){this.range=e}setHeight(e){this.height=Math.max(1,e)}setPadding(e,t){this.paddingTop=Math.max(0,e),this.paddingBottom=Math.max(0,t)}getRange(){return this.range}getPaddingTop(){return this.paddingTop}getPaddingBottom(){return this.paddingBottom}priceToY(e){let{maxPrice:t,minPrice:n}=this.range,r=t-n||1,i=(e-n)/r,a=Math.max(1,this.height-this.paddingTop-this.paddingBottom);return this.paddingTop+a*(1-i)}},I=class{id;top=0;height=0;priceRange={maxPrice:100,minPrice:0};yAxis=new F;renderers=[];constructor(e){this.id=e}setLayout(e,t){this.top=e,this.height=Math.max(1,t),this.yAxis.setHeight(this.height)}setPadding(e,t){this.yAxis.setPadding(e,t)}addRenderer(e){this.renderers.push(e)}updateRange(e,t){this.priceRange=P(e,t.start,t.end),this.yAxis.setRange(this.priceRange)}},L=class{chart;isDragging=!1;dragStartX=0;scrollStartX=0;isTouchSession=!1;crosshairPos=null;crosshairIndex=null;hoveredIndex=null;activePaneId=null;tooltipPos={x:0,y:0};tooltipSize={width:220,height:180};constructor(e){this.chart=e}onPointerDown(e){if(e.isPrimary===!1)return;this.isTouchSession=e.pointerType===`touch`,this.isDragging=!0,this.updateHoverFromPoint(e.clientX,e.clientY);let t=this.chart.getDom().container;this.dragStartX=e.clientX,this.scrollStartX=t.scrollLeft,this.chart.scheduleDraw()}onPointerMove(e){if(e.isPrimary===!1)return;let t=this.chart.getDom().container;if(this.isDragging){let n=this.dragStartX-e.clientX;t.scrollLeft=this.scrollStartX+n,this.updateHoverFromPoint(e.clientX,e.clientY),this.chart.scheduleDraw();return}this.updateHoverFromPoint(e.clientX,e.clientY),this.chart.scheduleDraw()}onPointerUp(e){e.isPrimary!==!1&&(this.isDragging=!1)}onPointerLeave(e){e.isPrimary!==!1&&(this.isDragging=!1,this.isTouchSession=!1,this.clearHover(),this.chart.scheduleDraw())}onMouseDown(e){if(this.isTouchSession||e.button!==0)return;let t=this.chart.getDom().container;this.isDragging=!0,this.dragStartX=e.clientX,this.scrollStartX=t.scrollLeft,this.updateHoverFromPoint(e.clientX,e.clientY),this.chart.scheduleDraw(),e.preventDefault()}onMouseMove(e){if(this.isTouchSession)return;let t=this.chart.getDom().container;if(this.isDragging){let n=this.dragStartX-e.clientX;t.scrollLeft=this.scrollStartX+n;return}this.updateHover(e),this.chart.scheduleDraw()}onMouseUp(){this.isTouchSession||(this.isDragging=!1)}onMouseLeave(){this.isTouchSession||(this.isDragging=!1,this.clearHover(),this.chart.scheduleDraw())}onScroll(){this.clearHover(),this.chart.scheduleDraw()}onWheel(e){let t=this.chart.getDom().container,n=t.getBoundingClientRect(),r=e.clientX-n.left,i=t.scrollLeft;this.clearHover(),this.chart.zoomAt(r,i,e.deltaY)}setTooltipSize(e){this.tooltipSize=e}clearHover(){this.crosshairPos=null,this.crosshairIndex=null,this.hoveredIndex=null,this.activePaneId=null}updateHover(e){this.updateHoverFromPoint(e.clientX,e.clientY)}updateHoverFromPoint(e,t){let n=this.chart.getDom().container,r=n.getBoundingClientRect(),i=e-r.left,a=t-r.top,o=this.chart.getOption(),s=Math.max(1,Math.round(r.width)),c=Math.max(1,Math.round(r.height)),l=s-o.rightAxisWidth,u=c-o.bottomAxisHeight;if(i<0||a<0||i>l||a>u){this.clearHover();return}let d=n.scrollLeft,f=o.kWidth+o.kGap,p=d+i-o.kGap;if(p<0){this.clearHover();return}let m=this.chart.getData(),h=Math.floor(p/f),g=this.chart.getPanes().find(e=>a>=e.top&&a<=e.top+e.height);if(g?this.activePaneId=g.id:this.activePaneId=null,h>=0&&h<(m?.length??0)){this.crosshairIndex=h;let e=o.kGap+h*f+o.kWidth/2-d;this.crosshairPos={x:Math.min(Math.max(e,0),l),y:Math.min(Math.max(a,0),u)}}else this.crosshairIndex=null,this.crosshairPos={x:Math.min(Math.max(i,0),l),y:Math.min(Math.max(a,0),u)};let _=typeof this.crosshairIndex==`number`?m[this.crosshairIndex]:void 0;if(!_||!g){this.hoveredIndex=null;return}let v=a-g.top,y=g.yAxis.priceToY(_.open),b=g.yAxis.priceToY(_.close),x=g.yAxis.priceToY(_.high),S=g.yAxis.priceToY(_.low),C=Math.min(y,b),w=Math.max(y,b),T=p-this.crosshairIndex*f,E=o.kWidth/2,D=v>=C&&v<=w&&T>=0&&T<=o.kWidth,O=Math.abs(T-E)<=3&&v>=x&&v<=S;if(!D&&!O){this.hoveredIndex=null;return}this.hoveredIndex=this.crosshairIndex;let k=this.tooltipSize.width,A=this.tooltipSize.height,j=i+14,M=i-14-k,N=j+k+12<=s?j:M,P=a+14,F=Math.max(12,s-k-12),I=Math.max(12,c-A-12);this.tooltipPos={x:Math.min(Math.max(N,12),F),y:Math.min(Math.max(P,12),I)}}};function R(e,t,n,r,i,a){let o=t-n||1,s=(e-n)/o;return i+Math.max(1,r-i-a)*(1-s)}function ee(e,t,n,r,i,a){let o=t-n||1,s=Math.max(1,r-i-a);return n+(1-(Math.min(Math.max(e,i),i+s)-i)/s)*o}function z(e,t){return Math.round(e*t)/t}function B(e,t){return(Math.floor(e*t)+.5)/t}function V(e,t,n,r,i){let a=z(e,i),o=z(t,i),s=z(e+n,i),c=z(t+r,i);return{x:a,y:o,width:Math.max(1/i,s-a),height:Math.max(1/i,c-o)}}function H(e,t,n,r){if(t===n)return null;let i=Math.min(t,n),a=Math.max(t,n),o=Math.round(e*r),s=Math.round(i*r),c=Math.round(a*r);return{x:o/r,y:s/r,width:1/r,height:Math.max(1,c-s)/r}}function U(e,t,n,r){if(e===t)return null;let i=Math.min(e,t),a=Math.max(e,t),o=Math.round(i*r),s=Math.round(a*r),c=Math.round(n*r);return{x:o/r,y:c/r,width:Math.max(1,s-o)/r,height:1/r}}function te(e,t){let{x:n,y:r,width:i,height:a,priceRange:o,yPaddingPx:s=0,dpr:c,ticks:l=10,bgColor:u=`rgba(255,255,255,0.85)`,textColor:d=`rgba(0,0,0,0.65)`,lineColor:f=`rgba(0,0,0,0.12)`,fontSize:p=16,paddingX:m=12}=t,h=s,g=Math.max(0,Math.min(h,Math.floor(a/2)-1)),{maxPrice:_,minPrice:v}=o,y=_-v,b=y===0?0:y/(Math.max(2,l)-1);e.fillStyle=u,e.fillRect(n,r,i,a),e.strokeStyle=f,e.lineWidth=1,e.beginPath(),e.moveTo(B(n,c),r),e.lineTo(B(n,c),r+a),e.stroke(),e.font=`${p}px -apple-system,BlinkMacSystemFont,Trebuchet MS,Roboto,Ubuntu,sans-serif`,e.textBaseline=`middle`,e.textAlign=`left`;let x=n+m;for(let t=0;t<Math.max(2,l);t++){let i=y===0?_:_-b*t,o=Math.round(R(i,_,v,a,g,g)+r);e.strokeStyle=f,e.beginPath();let s=B(o,c);e.moveTo(n,s),e.lineTo(n+4,s),e.stroke(),e.fillStyle=d,e.fillText(i.toFixed(2),z(x,c),z(o,c))}}function ne(e,t){let{x:n,y:r,width:i,height:o,crosshairX:s,timestamp:c,dpr:l,bgColor:u=`rgba(0,0,0,0.55)`,textColor:d=`rgba(255,255,255,0.92)`,fontSize:f=12,paddingX:p=8,paddingY:m=4}=t,h=a(c);e.save(),e.font=`${f}px -apple-system,BlinkMacSystemFont,Trebuchet MS,Roboto,Ubuntu,sans-serif`,e.textBaseline=`middle`,e.textAlign=`center`;let g=Math.ceil(e.measureText(h).width),_=Math.min(i,g+p*2),v=Math.min(o,f+m*2),y=Math.min(Math.max(s,n+_/2),n+i-_/2),b=r+o/2,x=y-_/2,S=b-v/2;e.fillStyle=u,e.fillRect(z(x,l),z(S,l),z(_,l),z(v,l)),e.fillStyle=d,e.fillText(h,z(y,l),z(b,l)),e.restore()}function re(e,t){let{x:n,y:r,width:i,height:a,crosshairY:o,priceRange:s,yPaddingPx:c=0,dpr:l,bgColor:u=`rgba(0,0,0,0.55)`,textColor:d=`rgba(255,255,255,0.92)`,fontSize:f=12,paddingX:p=12}=t,m=Math.max(0,Math.min(c,Math.floor(a/2)-1)),{maxPrice:h,minPrice:g}=s,_=ee(o-r,h,g,a,m,m).toFixed(2);e.save(),e.font=`${f}px -apple-system,BlinkMacSystemFont,Trebuchet MS,Roboto,Ubuntu,sans-serif`,e.textBaseline=`middle`,e.textAlign=`left`;let v=e.measureText(_),y=f+6,b=Math.ceil(v.width+p*2),x=y,S=Math.min(i,b),C=Math.min(Math.max(o,r+x/2),r+a-x/2),w=C-x/2;e.fillStyle=u,e.fillRect(z(n,l),z(w,l),z(S,l),z(x,l)),e.fillStyle=d;let T=n+p;e.fillText(_,z(T,l),z(C,l)),e.restore()}function ie(e,t){let{x:i,y:a,width:o,height:s,data:c,scrollLeft:l,kWidth:u,kGap:d,startIndex:f,endIndex:p,dpr:m,bgColor:h=`rgba(255,255,255,0.85)`,textColor:g=`rgba(0,0,0,0.65)`,lineColor:_=`rgba(0,0,0,0.12)`,fontSize:v=16,paddingX:y=12}=t,b=u+d;e.fillStyle=h,e.fillRect(i,a,o,s),e.strokeStyle=_,e.lineWidth=1,e.beginPath(),e.moveTo(i,B(a,m)),e.lineTo(i+o,B(a,m)),e.stroke(),e.textAlign=`center`,e.textBaseline=`middle`;let x=a+s/2;for(let t=Math.max(f,1);t<p&&t<c.length;t++){let i=c[t],s=c[t-1];if(!(!i||!s)&&r(i.timestamp)!==r(s.timestamp)){let r=d+t*b-l,s=y,c=Math.max(y,o-y);if(r>=s&&r<=c){let t=Math.min(Math.max(r,s),c);e.strokeStyle=_,e.beginPath();let o=B(t,m);e.moveTo(o,a),e.lineTo(o,a+4),e.stroke();let{text:l,isYear:u}=n(i.timestamp);e.fillStyle=g,e.font=`${u?`bold `:``}${v}px -apple-system,BlinkMacSystemFont,Trebuchet MS,Roboto,Ubuntu,sans-serif`,e.fillText(l,z(t,m),z(x,m))}}}}function ae(e){return{draw({ctx:t,pane:n,dpr:r}){let i=typeof e.ticks==`number`?e.ticks:Math.max(2,Math.min(8,Math.round(n.height/80)));te(t,{x:e.axisX,y:n.top,width:e.axisWidth,height:n.height,priceRange:n.priceRange,yPaddingPx:e.yPaddingPx,dpr:r,ticks:i})}}}function oe(e){let{ctx:t,data:n,scrollLeft:r,kWidth:i,kGap:a,startIndex:o,endIndex:s,dpr:c,crosshair:l}=e,u=t.canvas.width/c,d=t.canvas.height/c;if(t.setTransform(1,0,0,1,0,0),t.scale(c,c),t.clearRect(0,0,u,d),ie(t,{x:0,y:0,width:u,height:d,data:n,scrollLeft:r,kWidth:i,kGap:a,startIndex:o,endIndex:s,dpr:c}),l&&typeof l.index==`number`){let e=n[l.index];e&&ne(t,{x:0,y:0,width:u,height:d,crosshairX:l.x,timestamp:e.timestamp,dpr:c})}}function W(e){let{ctx:t,plotWidth:n,plotHeight:r,dpr:i,x:a,y:o}=e;t.save(),t.beginPath(),t.rect(0,0,n,r),t.clip(),t.fillStyle=`rgba(0,0,0,0.28)`;let s=H(a,0,r,i);s&&t.fillRect(s.x,s.y,s.width,s.height);let c=U(0,n,o,i);c&&t.fillRect(c.x,c.y,c.width,c.height),t.restore()}function G(e){let{ctx:t,pane:n,axisWidth:r,dpr:i,crosshairY:a,yPaddingPx:o}=e;re(t,{x:0,y:n.top,width:r,height:n.height,crosshairY:a,priceRange:n.priceRange,yPaddingPx:o,dpr:i})}function K(e,t,n){if(t<n-1)return;let r=0;for(let i=0;i<n;i++){let n=e[t-i];if(!n)return;r+=n.close}return r/n}const q=`rgba(255, 193, 37, 1)`,J=`rgba(190, 131, 12, 1)`,Y=`rgba(69, 112, 249, 1)`;function X(e,t,n,r,i,a,o,s,c,l){if(t.length<c)return;let u=r,d=n.yPaddingPx??0,f=Math.max(0,Math.min(d,Math.floor(u/2)-1)),p=f,m=f,h,g;if(s)h=s.maxPrice,g=s.minPrice;else{h=-1/0,g=1/0;for(let e=a;e<o&&e<t.length;e++){let n=t[e];n&&(n.high>h&&(h=n.high),n.low<g&&(g=n.low))}}if(!Number.isFinite(h)||!Number.isFinite(g))return;let _=n.kWidth+n.kGap;e.strokeStyle=l,e.lineWidth=1,e.lineJoin=`round`,e.lineCap=`round`,e.beginPath();let v=!0,y=Math.max(a,c-1);for(let r=y;r<o&&r<t.length;r++){let a=0;for(let e=0;e<c;e++){let n=t[r-e];if(!n)return;a+=n.close}let o=a/c,s=n.kGap+r*_+n.kWidth/2,l=R(o,h,g,u,p,m),d=B(s,i),f=B(l,i);v?(e.moveTo(d,f),v=!1):e.lineTo(d,f)}e.stroke()}function se(e,t,n,r,i=1,a=0,o=t.length,s){X(e,t,n,r,i,a,o,s,5,q)}function ce(e,t,n,r,i=1,a=0,o=t.length,s){X(e,t,n,r,i,a,o,s,10,J)}function le(e,t,n,r,i=1,a=0,o=t.length,s){X(e,t,n,r,i,a,o,s,20,Y)}function ue(e){let{ctx:t,data:n,endIndex:r,showMA:i}=e;if(!n.length)return;t.save(),t.font=`12px Arial`,t.textBaseline=`top`,t.textAlign=`left`;let a=Math.min(r-1,n.length-1),o=[];if(i.ma5&&o.push({label:`MA5`,color:q,value:K(n,a,5)}),i.ma10&&o.push({label:`MA10`,color:J,value:K(n,a,10)}),i.ma20&&o.push({label:`MA20`,color:Y,value:K(n,a,20)}),o.length>0){let e=t.measureText(`均线`).width+10;for(let n of o){let r=typeof n.value==`number`?` ${n.value.toFixed(2)}`:``;e+=t.measureText(`${n.label}${r}`).width+10}e-=10;let n=Math.ceil(e+16);t.fillStyle=`rgba(255,255,255,0.85)`,t.fillRect(8,8,n,24);let r=16;t.fillStyle=`#333`,t.fillText(`均线`,r,14),r+=t.measureText(`均线`).width+10;for(let e of o){let n=typeof e.value==`number`?` ${e.value.toFixed(2)}`:``,i=`${e.label}${n}`;t.fillStyle=e.color,t.fillText(i,r,14),r+=t.measureText(i).width+10}}t.restore()}function de(e){let{ctx:t,dpr:n,paneTop:r,title:i}=e;t.save(),t.font=`12px Arial`,t.textBaseline=`top`,t.textAlign=`left`,t.fillStyle=`rgba(0,0,0,0.55)`;let a=r+8;t.fillText(i,8,a),t.restore()}function fe(e){let{ctx:t,dpr:n,width:r,panes:i,color:a=`rgba(0,0,0,0.12)`,omitOuterTop:o=!1,omitOuterRight:s=!1,omitOuterBottom:c=!1,omitOuterLeft:l=!1}=e;if(!i.length)return;t.save(),t.strokeStyle=a,t.lineWidth=1;let u=B(0,n),d=B(r,n),f=1/0,p=-1/0;for(let e of i)f=Math.min(f,e.top),p=Math.max(p,e.top+e.height);f=Number.isFinite(f)?f:0,p=Number.isFinite(p)?p:0;for(let e of i){let r=B(e.top,n),i=B(e.top+e.height,n),a=Math.abs(e.top-f)<1e-6,m=Math.abs(e.top+e.height-p)<1e-6;t.beginPath(),o&&a||(t.moveTo(u,r),t.lineTo(d,r)),s||(t.moveTo(d,r),t.lineTo(d,i)),c&&m||(t.moveTo(u,i),t.lineTo(d,i)),l||(t.moveTo(u,r),t.lineTo(u,i)),t.stroke()}t.restore()}var pe=class{dom;opt;data=[];raf=null;viewport=null;panes=[];interaction;onZoomChange;setOnZoomChange(e){this.onZoomChange=e}constructor(e,t){this.dom=e,this.opt=t,this.interaction=new L(this),this.initPanes()}getPanes(){return this.panes}setPaneRenderers(e,t){let n=this.panes.find(t=>t.id===e);if(n){n.renderers.length=0;for(let e of t)n.renderers.push(e);this.scheduleDraw()}}getDom(){return this.dom}getOption(){return this.opt}updateOptions(e){this.opt={...this.opt,...e},e.panes&&this.initPanes(),this.resize()}updateData(e){this.data=e??[],this.scheduleDraw()}getData(){return this.data}getContentWidth(){let e=this.data?.length??0;return this.opt.kGap+e*(this.opt.kWidth+this.opt.kGap)+this.opt.rightAxisWidth}resize(){this.computeViewport(),this.layoutPanes(),this.scheduleDraw()}scheduleDraw(){this.raf!=null&&cancelAnimationFrame(this.raf),this.raf=requestAnimationFrame(()=>{this.raf=null,this.draw()})}draw(){let e=this.computeViewport();if(!e)return;let t=this.dom.plotCanvas.getContext(`2d`),n=this.dom.yAxisCanvas.getContext(`2d`),r=this.dom.xAxisCanvas.getContext(`2d`);if(!t||!n||!r)return;t.setTransform(1,0,0,1,0,0),t.scale(e.dpr,e.dpr),t.clearRect(0,0,e.plotWidth,e.plotHeight),n.setTransform(1,0,0,1,0,0),n.scale(e.dpr,e.dpr),n.clearRect(0,0,this.opt.rightAxisWidth,e.plotHeight);let{start:i,end:a}=N(e.scrollLeft,e.plotWidth,this.opt.kWidth,this.opt.kGap,this.data.length),o={start:i,end:a};for(let r of this.panes){r.updateRange(this.data,o),t.save(),t.beginPath(),t.rect(0,r.top,e.plotWidth,r.height),t.clip(),t.translate(0,r.top);for(let n of r.renderers)n.draw({ctx:t,pane:r,data:this.data,range:o,scrollLeft:e.scrollLeft,kWidth:this.opt.kWidth,kGap:this.opt.kGap,dpr:e.dpr});t.restore(),ae({axisX:0,axisWidth:this.opt.rightAxisWidth,yPaddingPx:this.opt.yPaddingPx,ticks:r.id===`sub`?2:void 0}).draw({ctx:n,pane:r,data:this.data,range:o,scrollLeft:e.scrollLeft,kWidth:this.opt.kWidth,kGap:this.opt.kGap,dpr:e.dpr}),this.interaction.crosshairPos&&this.interaction.activePaneId===r.id&&G({ctx:n,pane:r,axisWidth:this.opt.rightAxisWidth,dpr:e.dpr,crosshairY:this.interaction.crosshairPos.y,yPaddingPx:this.opt.yPaddingPx})}fe({ctx:t,dpr:e.dpr,width:e.plotWidth,panes:[{top:0,height:e.plotHeight}]});let s=this.panes.find(e=>e.id===`sub`);s&&de({ctx:t,dpr:e.dpr,paneTop:s.top,title:`副图(占位)`}),oe({ctx:r,data:this.data,scrollLeft:e.scrollLeft,kWidth:this.opt.kWidth,kGap:this.opt.kGap,startIndex:o.start,endIndex:o.end,dpr:e.dpr,crosshair:this.interaction.crosshairPos&&typeof this.interaction.crosshairIndex==`number`?{x:this.interaction.crosshairPos.x,index:this.interaction.crosshairIndex}:null}),this.interaction.crosshairPos&&(t.save(),t.beginPath(),t.rect(0,0,e.plotWidth,e.plotHeight),t.clip(),W({ctx:t,plotWidth:e.plotWidth,plotHeight:e.plotHeight,dpr:e.dpr,x:this.interaction.crosshairPos.x,y:this.interaction.crosshairPos.y}),t.restore()),ue({ctx:t,data:this.data,endIndex:o.end,showMA:{ma5:!0,ma10:!0,ma20:!0},dpr:e.dpr})}zoomAt(e,t,n){let r=this.opt.kWidth+this.opt.kGap,i=(t+e)/r,a=n>0?-1:1,o=Math.max(this.opt.minKWidth,Math.min(this.opt.maxKWidth,this.opt.kWidth+a));if(o===this.opt.kWidth)return;let s=this.opt.kGap/this.opt.kWidth,c=Math.max(.5,o*s);this.opt={...this.opt,kWidth:o,kGap:c};let l=i*(o+c)-e;if(this.onZoomChange){this.onZoomChange(o,c,l);return}let u=this.dom.container,d=Math.max(0,u.scrollWidth-u.clientWidth);u.scrollLeft=Math.min(Math.max(0,l),d),this.scheduleDraw()}destroy(){this.raf!=null&&cancelAnimationFrame(this.raf),this.raf=null,this.viewport=null,this.panes=[],this.onZoomChange=void 0}initPanes(){this.panes=this.opt.panes.map(e=>new I(e.id))}layoutPanes(){let e=this.viewport;if(!e)return;let t=this.opt.panes.reduce((e,t)=>e+(t.ratio??0),0)||1,n=Math.max(0,this.opt.paneGap??0),r=0,i=Math.min(this.panes.length,this.opt.panes.length),a=n*Math.max(0,i-1),o=Math.max(1,e.plotHeight-a);for(let e=0;e<i;e++){let a=this.opt.panes[e],s=this.panes[e];if(!a||!s)continue;let c=e===i-1?o-r:Math.round(o*(a.ratio/t));s.setLayout(r,c),s.setPadding(this.opt.yPaddingPx,this.opt.yPaddingPx),r+=c+n}}computeViewport(){let e=this.dom.container;if(!e)return null;let t=e.getBoundingClientRect(),n=Math.max(1,Math.round(t.width)),r=Math.max(1,Math.round(t.height)),i=e.scrollLeft,a=n-this.opt.rightAxisWidth,o=r-this.opt.bottomAxisHeight,s=window.devicePixelRatio||1,c=16*1024*1024;n*s*(r*s)>c&&(s=Math.sqrt(c/(n*r))),this.dom.canvasLayer.style.width=`${n}px`,this.dom.canvasLayer.style.height=`${r}px`,this.dom.plotCanvas.style.width=`${a}px`,this.dom.plotCanvas.style.height=`${o}px`,this.dom.plotCanvas.width=Math.round(a*s),this.dom.plotCanvas.height=Math.round(o*s),this.dom.yAxisCanvas.style.width=`${this.opt.rightAxisWidth}px`,this.dom.yAxisCanvas.style.height=`${o}px`,this.dom.yAxisCanvas.width=Math.round(this.opt.rightAxisWidth*s),this.dom.yAxisCanvas.height=Math.round(o*s),this.dom.xAxisCanvas.style.width=`${a}px`,this.dom.xAxisCanvas.style.height=`${this.opt.bottomAxisHeight}px`,this.dom.xAxisCanvas.width=Math.round(a*s),this.dom.xAxisCanvas.height=Math.round(this.opt.bottomAxisHeight*s);let l={viewWidth:n,viewHeight:r,plotWidth:a,plotHeight:o,scrollLeft:i,dpr:s};return this.viewport=l,l}};function me(e){return e.open>e.close?`down`:e.open<e.close?`up`:`flat`}var he=`rgba(214, 10, 34, 1)`,ge=`rgba(3, 123, 102, 1)`;const _e={draw({ctx:e,pane:t,data:n,range:r,scrollLeft:i,kWidth:a,kGap:o,dpr:s}){if(!n.length)return;let c=a+o;e.save(),e.translate(-i,0);for(let i=r.start;i<r.end&&i<n.length;i++){let r=n[i];if(!r)continue;let l=t.yAxis.priceToY(r.open),u=t.yAxis.priceToY(r.close),d=t.yAxis.priceToY(r.high),f=t.yAxis.priceToY(r.low),p=o+i*c,m=V(p,Math.min(l,u),a,Math.max(Math.abs(l-u),1),s);e.fillStyle=me(r)===`up`?he:ge,e.fillRect(m.x,m.y,m.width,m.height);let h=p+a/2,g=m.y,_=m.y+m.height,v=Math.max(r.open,r.close),y=Math.min(r.open,r.close);if(r.high>v){let t=H(h,d,g,s);t&&e.fillRect(t.x,t.y,t.width,t.height)}if(r.low<y){let t=H(h,_,f,s);t&&e.fillRect(t.x,t.y,t.width,t.height)}}e.restore()}},Z={draw({ctx:e,pane:t,data:n,range:r,scrollLeft:i,kWidth:a,kGap:o,dpr:s}){if(!n.length)return;let c=a+o,l=t.id===`main`?6:2;e.save(),e.fillStyle=`rgba(0,0,0,0.06)`,e.translate(-i,0);let u=e.canvas.width/s,d=i,f=i+u,p=t.yAxis.getPaddingTop(),m=t.yAxis.getPaddingBottom(),h=p,g=Math.max(p,t.height-m),_=Math.max(0,g-h);for(let t=0;t<l;t++){let n=l<=1?0:t/(l-1),r=U(d,f,Math.round(h+n*_),s);r&&e.fillRect(r.x,r.y,r.width,r.height)}function v(e){let t=new Date(e);return`${t.getFullYear()}-${t.getMonth()}`}for(let i=Math.max(r.start,1);i<r.end&&i<n.length;i++){let r=n[i],a=n[i-1];if(!(!r||!a)&&v(r.timestamp)!==v(a.timestamp)){let n=H(o+i*c,0,t.height,s);n&&e.fillRect(n.x,n.y,n.width,n.height)}}e.restore()}},ve={draw({ctx:e,pane:t,data:n,range:r,scrollLeft:i,kWidth:a,kGap:o,dpr:s}){let c=n[n.length-1];if(!c)return;e.save(),e.translate(-i,0);let l=Math.round(t.yAxis.priceToY(c.close)),u=a+o,d=o+r.start*u,f=o+r.end*u;e.strokeStyle=`#F59999`,e.lineWidth=1,e.setLineDash([4,3]),e.beginPath();let p=(Math.floor(l*s)+.5)/s;e.moveTo(Math.round(d*s)/s,p),e.lineTo(Math.round(f*s)/s,p),e.stroke(),e.setLineDash([]),e.restore()}};function ye(e){return{draw({ctx:t,pane:n,data:r,range:i,scrollLeft:a,kWidth:o,kGap:s,dpr:c}){t.save(),t.translate(-a,0);let l={kWidth:o,kGap:s,yPaddingPx:0};e.ma5&&se(t,r,l,n.height,c,i.start,i.end,n.priceRange),e.ma10&&ce(t,r,l,n.height,c,i.start,i.end,n.priceRange),e.ma20&&le(t,r,l,n.height,c,i.start,i.end,n.priceRange),t.restore()}}}const be={draw({ctx:e,pane:t,data:n,range:r,scrollLeft:i,kWidth:a,kGap:o,dpr:s}){if(!n.length||t.id!==`main`)return;let c=Math.max(0,r.start),l=Math.min(n.length,r.end);if(l-c<=0)return;let u=-1/0,d=1/0,f=c,p=c;for(let e=c;e<l;e++){let t=n[e];t&&(t.high>=u&&(u=t.high,f=e),t.low<=d&&(d=t.low,p=e))}if(!Number.isFinite(u)||!Number.isFinite(d))return;let m=a+o,h=e=>o+e*m+a/2;e.save(),e.translate(-i,0),Q(e,h(f),t.yAxis.priceToY(u),u,s),Q(e,h(p),t.yAxis.priceToY(d),d,s),e.restore()}};function Q(e,t,n,r,i){let a=r.toFixed(2),o=U(t,t+30,n,i);o&&(e.fillStyle=`rgba(0,0,0,0.45)`,e.fillRect(o.x,o.y,o.width,o.height));let s=z(t+30,i),c=z(n,i);e.fillStyle=`rgba(0,0,0,0.45)`,e.beginPath(),e.arc(s,c,2,0,Math.PI*2),e.fill(),e.font=`12px Arial`,e.textBaseline=`middle`,e.textAlign=`left`,e.fillStyle=`rgba(0,0,0,0.70)`,e.fillText(a,z(t+30+4,i),z(n,i))}var xe={class:`chart-wrapper`},Se=(0,e.defineComponent)({__name:`KLineChart`,props:{data:{},kWidth:{default:10},kGap:{default:2},yPaddingPx:{default:0},showMA:{default:()=>({ma5:!0,ma10:!0,ma20:!0})},autoScrollToRight:{type:Boolean,default:!0},minKWidth:{default:2},maxKWidth:{default:50},rightAxisWidth:{default:70},bottomAxisHeight:{default:24},paneRatios:{default:()=>[.75,.25]}},setup(t,{expose:n}){let r=t,i=(0,e.ref)(null),a=(0,e.ref)(null),o=(0,e.ref)(null),s=(0,e.ref)(null),c=(0,e.ref)(null),l=(0,e.ref)(r.kWidth),u=(0,e.ref)(r.kGap),d=(0,e.shallowRef)(null);function f(){d.value?.scheduleDraw()}let p=(0,e.ref)(null);function m(e){if(p.value=e,!e)return;let t=e.getBoundingClientRect();d.value?.interaction.setTooltipSize({width:Math.max(180,Math.round(t.width)),height:Math.max(80,Math.round(t.height))})}let h=(0,e.ref)(!1),g=(0,e.ref)(null),_=(0,e.ref)({x:0,y:0}),v=(0,e.computed)(()=>{let e=g.value;return typeof e==`number`?r.data?.[e]??null:null}),y=(0,e.computed)(()=>g.value),b=(0,e.computed)(()=>_.value);function x(){let e=d.value?.interaction;if(!e){g.value=null;return}g.value=e.hoveredIndex??null;let t=e.tooltipPos;t&&(_.value={x:t.x,y:t.y})}function S(e){h.value=!0,d.value?.interaction.onMouseDown(e),x()}function C(e){h.value=!0,d.value?.interaction.onPointerDown(e),x()}function w(e){d.value?.interaction.onMouseMove(e),x()}function T(e){d.value?.interaction.onPointerMove(e),x()}function E(){h.value=!1,d.value?.interaction.onMouseUp(),x()}function D(e){h.value=!1,d.value?.interaction.onPointerUp(e),x()}function O(){h.value=!1,d.value?.interaction.onMouseLeave(),g.value=null}function k(e){h.value=!1,d.value?.interaction.onPointerLeave(e),g.value=null}function A(){d.value?.interaction.onScroll(),x()}function j(e){d.value?.interaction.onWheel(e),x()}let N=(0,e.computed)(()=>{let e=r.data?.length??0;return u.value+e*(l.value+u.value)+r.rightAxisWidth});function P(){let e=c.value;e&&(e.scrollLeft=e.scrollWidth,f())}return n({scheduleRender:f,scrollToRight:P}),(0,e.onMounted)(()=>{let t=c.value,n=s.value,p=i.value,m=a.value,h=o.value;if(!t||!n||!p||!m||!h)return;let g=[{id:`main`,ratio:r.paneRatios[0]},{id:`sub`,ratio:r.paneRatios[1]}],_=new pe({container:t,canvasLayer:n,plotCanvas:p,yAxisCanvas:m,xAxisCanvas:h},{kWidth:l.value,kGap:u.value,yPaddingPx:r.yPaddingPx,rightAxisWidth:r.rightAxisWidth,bottomAxisHeight:r.bottomAxisHeight,minKWidth:r.minKWidth,maxKWidth:r.maxKWidth,panes:g,paneGap:0});_.setOnZoomChange(async(t,n,r)=>{l.value=t,u.value=n,await(0,e.nextTick)(),await new Promise(e=>requestAnimationFrame(()=>e()));let i=c.value;if(!i)return;let a=Math.max(0,i.scrollWidth-i.clientWidth);i.scrollLeft=Math.min(Math.max(0,r),a),f()}),_.setPaneRenderers(`main`,[Z,ve,_e,be,ye(r.showMA)]),_.setPaneRenderers(`sub`,[Z]),d.value=_,_.updateData(r.data),_.resize();let v=()=>_.resize();window.addEventListener(`resize`,v,{passive:!0}),_.__onResize=v}),(0,e.onUnmounted)(()=>{let e=d.value;if(e){let t=e.__onResize;t&&window.removeEventListener(`resize`,t),e.destroy()}d.value=null}),(0,e.watch)(()=>[r.kWidth,r.kGap],([e,t])=>{typeof e==`number`&&(l.value=e),typeof t==`number`&&(u.value=t),d.value?.updateOptions({kWidth:l.value,kGap:u.value})}),(0,e.watch)(()=>[r.data,r.yPaddingPx,r.showMA],async()=>{d.value?.updateOptions({yPaddingPx:r.yPaddingPx}),d.value?.updateData(r.data),r.autoScrollToRight?(await(0,e.nextTick)(),P()):f()},{deep:!0}),(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,xe,[(0,e.createElementVNode)(`div`,{class:(0,e.normalizeClass)([`chart-container`,{"is-dragging":h.value}]),ref_key:`containerRef`,ref:c,onScrollPassive:A,onMousedown:S,onMousemove:w,onMouseup:E,onMouseleave:O,onPointerdown:C,onPointermove:T,onPointerup:D,onPointerleave:k,onWheel:(0,e.withModifiers)(j,[`prevent`])},[(0,e.createElementVNode)(`div`,{class:`scroll-content`,style:(0,e.normalizeStyle)({width:N.value+`px`})},[(0,e.createElementVNode)(`div`,{class:`canvas-layer`,ref_key:`canvasLayerRef`,ref:s},[(0,e.createElementVNode)(`canvas`,{class:`plot-canvas`,ref_key:`plotCanvasRef`,ref:i},null,512),(0,e.createElementVNode)(`canvas`,{class:`y-axis-canvas`,ref_key:`yAxisCanvasRef`,ref:a},null,512),(0,e.createElementVNode)(`canvas`,{class:`x-axis-canvas`,ref_key:`xAxisCanvasRef`,ref:o},null,512),v.value?((0,e.openBlock)(),(0,e.createBlock)(M,{key:0,k:v.value,index:y.value,data:r.data,pos:b.value,"set-el":m},null,8,[`k`,`index`,`data`,`pos`])):(0,e.createCommentVNode)(``,!0)],512)],4)],34)]))}}),Ce=j(Se,[[`__scopeId`,`data-v-28c7f9b2`]]);const $=Ce,we={install(e){e.component(`KLineChart`,$)}};exports.KLineChart=$,exports.KMapPlugin=we;