@qfo/qfchart 0.8.0 → 0.8.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.
- package/dist/index.d.ts +524 -12
- package/dist/qfchart.min.browser.js +34 -18
- package/dist/qfchart.min.es.js +34 -18
- package/package.json +1 -1
- package/src/QFChart.ts +109 -272
- package/src/components/AbstractPlugin.ts +234 -104
- package/src/components/DrawingEditor.ts +297 -248
- package/src/components/DrawingRendererRegistry.ts +13 -0
- package/src/components/GraphicBuilder.ts +2 -2
- package/src/components/LayoutManager.ts +92 -52
- package/src/components/SeriesBuilder.ts +10 -10
- package/src/components/TooltipFormatter.ts +1 -1
- package/src/index.ts +25 -6
- package/src/plugins/ABCDPatternTool/ABCDPatternDrawingRenderer.ts +112 -0
- package/src/plugins/ABCDPatternTool/ABCDPatternTool.ts +136 -0
- package/src/plugins/ABCDPatternTool/index.ts +2 -0
- package/src/plugins/CrossLineTool/CrossLineDrawingRenderer.ts +49 -0
- package/src/plugins/CrossLineTool/CrossLineTool.ts +52 -0
- package/src/plugins/CrossLineTool/index.ts +2 -0
- package/src/plugins/CypherPatternTool/CypherPatternDrawingRenderer.ts +80 -0
- package/src/plugins/CypherPatternTool/CypherPatternTool.ts +84 -0
- package/src/plugins/CypherPatternTool/index.ts +2 -0
- package/src/plugins/ExtendedLineTool/ExtendedLineDrawingRenderer.ts +73 -0
- package/src/plugins/ExtendedLineTool/ExtendedLineTool.ts +173 -0
- package/src/plugins/ExtendedLineTool/index.ts +2 -0
- package/src/plugins/FibSpeedResistanceFanTool/FibSpeedResistanceFanDrawingRenderer.ts +163 -0
- package/src/plugins/FibSpeedResistanceFanTool/FibSpeedResistanceFanTool.ts +210 -0
- package/src/plugins/FibSpeedResistanceFanTool/index.ts +2 -0
- package/src/plugins/FibTrendExtensionTool/FibTrendExtensionDrawingRenderer.ts +141 -0
- package/src/plugins/FibTrendExtensionTool/FibTrendExtensionTool.ts +188 -0
- package/src/plugins/FibTrendExtensionTool/index.ts +2 -0
- package/src/plugins/FibonacciChannelTool/FibonacciChannelDrawingRenderer.ts +128 -0
- package/src/plugins/FibonacciChannelTool/FibonacciChannelTool.ts +231 -0
- package/src/plugins/FibonacciChannelTool/index.ts +2 -0
- package/src/plugins/FibonacciTool/FibonacciDrawingRenderer.ts +107 -0
- package/src/plugins/{FibonacciTool.ts → FibonacciTool/FibonacciTool.ts} +195 -192
- package/src/plugins/FibonacciTool/index.ts +2 -0
- package/src/plugins/HeadAndShouldersTool/HeadAndShouldersDrawingRenderer.ts +95 -0
- package/src/plugins/HeadAndShouldersTool/HeadAndShouldersTool.ts +97 -0
- package/src/plugins/HeadAndShouldersTool/index.ts +2 -0
- package/src/plugins/HorizontalLineTool/HorizontalLineDrawingRenderer.ts +54 -0
- package/src/plugins/HorizontalLineTool/HorizontalLineTool.ts +52 -0
- package/src/plugins/HorizontalLineTool/index.ts +2 -0
- package/src/plugins/HorizontalRayTool/HorizontalRayDrawingRenderer.ts +34 -0
- package/src/plugins/HorizontalRayTool/HorizontalRayTool.ts +52 -0
- package/src/plugins/HorizontalRayTool/index.ts +2 -0
- package/src/plugins/InfoLineTool/InfoLineDrawingRenderer.ts +72 -0
- package/src/plugins/InfoLineTool/InfoLineTool.ts +130 -0
- package/src/plugins/InfoLineTool/index.ts +2 -0
- package/src/plugins/LineTool/LineDrawingRenderer.ts +49 -0
- package/src/plugins/{LineTool.ts → LineTool/LineTool.ts} +161 -190
- package/src/plugins/LineTool/index.ts +2 -0
- package/src/plugins/{MeasureTool.ts → MeasureTool/MeasureTool.ts} +324 -344
- package/src/plugins/MeasureTool/index.ts +1 -0
- package/src/plugins/RayTool/RayDrawingRenderer.ts +69 -0
- package/src/plugins/RayTool/RayTool.ts +162 -0
- package/src/plugins/RayTool/index.ts +2 -0
- package/src/plugins/ThreeDrivesPatternTool/ThreeDrivesPatternDrawingRenderer.ts +106 -0
- package/src/plugins/ThreeDrivesPatternTool/ThreeDrivesPatternTool.ts +98 -0
- package/src/plugins/ThreeDrivesPatternTool/index.ts +2 -0
- package/src/plugins/ToolGroup.ts +211 -0
- package/src/plugins/TrendAngleTool/TrendAngleDrawingRenderer.ts +87 -0
- package/src/plugins/TrendAngleTool/TrendAngleTool.ts +176 -0
- package/src/plugins/TrendAngleTool/index.ts +2 -0
- package/src/plugins/TrianglePatternTool/TrianglePatternDrawingRenderer.ts +107 -0
- package/src/plugins/TrianglePatternTool/TrianglePatternTool.ts +98 -0
- package/src/plugins/TrianglePatternTool/index.ts +2 -0
- package/src/plugins/VerticalLineTool/VerticalLineDrawingRenderer.ts +35 -0
- package/src/plugins/VerticalLineTool/VerticalLineTool.ts +52 -0
- package/src/plugins/VerticalLineTool/index.ts +2 -0
- package/src/plugins/XABCDPatternTool/XABCDPatternDrawingRenderer.ts +178 -0
- package/src/plugins/XABCDPatternTool/XABCDPatternTool.ts +213 -0
- package/src/plugins/XABCDPatternTool/index.ts +2 -0
- package/src/types.ts +39 -11
|
@@ -1,104 +1,234 @@
|
|
|
1
|
-
import { ChartContext, Plugin, PluginConfig, OHLCV } from "../types";
|
|
2
|
-
import { EventType, EventHandler } from "../utils/EventBus";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
public
|
|
7
|
-
public
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
protected
|
|
39
|
-
|
|
40
|
-
public
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
this.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
import { ChartContext, Plugin, PluginConfig, OHLCV } from "../types";
|
|
2
|
+
import { EventType, EventHandler } from "../utils/EventBus";
|
|
3
|
+
import * as echarts from "echarts";
|
|
4
|
+
|
|
5
|
+
export abstract class AbstractPlugin implements Plugin {
|
|
6
|
+
public id: string;
|
|
7
|
+
public name?: string;
|
|
8
|
+
public icon?: string;
|
|
9
|
+
|
|
10
|
+
protected context!: ChartContext;
|
|
11
|
+
private eventListeners: Array<{ event: EventType; handler: EventHandler }> =
|
|
12
|
+
[];
|
|
13
|
+
|
|
14
|
+
// Snap indicator
|
|
15
|
+
private _snapIndicator: any = null;
|
|
16
|
+
private _snapMoveHandler: ((e: any) => void) | null = null;
|
|
17
|
+
private _snapKeyDownHandler: ((e: KeyboardEvent) => void) | null = null;
|
|
18
|
+
private _snapKeyUpHandler: ((e: KeyboardEvent) => void) | null = null;
|
|
19
|
+
private _snapBlurHandler: (() => void) | null = null;
|
|
20
|
+
private _snapActive: boolean = false;
|
|
21
|
+
private _lastMouseEvent: any = null;
|
|
22
|
+
|
|
23
|
+
constructor(config: PluginConfig) {
|
|
24
|
+
this.id = config.id;
|
|
25
|
+
this.name = config.name;
|
|
26
|
+
this.icon = config.icon;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public init(context: ChartContext): void {
|
|
30
|
+
this.context = context;
|
|
31
|
+
this.onInit();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Lifecycle hook called after context is initialized.
|
|
36
|
+
* Override this instead of init().
|
|
37
|
+
*/
|
|
38
|
+
protected onInit(): void {}
|
|
39
|
+
|
|
40
|
+
public activate(): void {
|
|
41
|
+
this.onActivate();
|
|
42
|
+
this._bindSnapIndicator();
|
|
43
|
+
this.context.events.emit("plugin:activated", this.id);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Lifecycle hook called when the plugin is activated.
|
|
48
|
+
*/
|
|
49
|
+
protected onActivate(): void {}
|
|
50
|
+
|
|
51
|
+
public deactivate(): void {
|
|
52
|
+
this._unbindSnapIndicator();
|
|
53
|
+
this.onDeactivate();
|
|
54
|
+
this.context.events.emit("plugin:deactivated", this.id);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Lifecycle hook called when the plugin is deactivated.
|
|
59
|
+
*/
|
|
60
|
+
protected onDeactivate(): void {}
|
|
61
|
+
|
|
62
|
+
public destroy(): void {
|
|
63
|
+
this._unbindSnapIndicator();
|
|
64
|
+
this.removeAllListeners();
|
|
65
|
+
this.onDestroy();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Lifecycle hook called when the plugin is destroyed.
|
|
70
|
+
*/
|
|
71
|
+
protected onDestroy(): void {}
|
|
72
|
+
|
|
73
|
+
// --- Helper Methods ---
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Register an event listener that will be automatically cleaned up on destroy.
|
|
77
|
+
*/
|
|
78
|
+
protected on(event: EventType, handler: EventHandler): void {
|
|
79
|
+
this.context.events.on(event, handler);
|
|
80
|
+
this.eventListeners.push({ event, handler });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Remove a specific event listener.
|
|
85
|
+
*/
|
|
86
|
+
protected off(event: EventType, handler: EventHandler): void {
|
|
87
|
+
this.context.events.off(event, handler);
|
|
88
|
+
this.eventListeners = this.eventListeners.filter(
|
|
89
|
+
(l) => l.event !== event || l.handler !== handler
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Remove all listeners registered by this plugin.
|
|
95
|
+
*/
|
|
96
|
+
protected removeAllListeners(): void {
|
|
97
|
+
this.eventListeners.forEach(({ event, handler }) => {
|
|
98
|
+
this.context.events.off(event, handler);
|
|
99
|
+
});
|
|
100
|
+
this.eventListeners = [];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Access to the ECharts instance.
|
|
105
|
+
*/
|
|
106
|
+
protected get chart() {
|
|
107
|
+
return this.context.getChart();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Access to market data.
|
|
112
|
+
*/
|
|
113
|
+
protected get marketData(): OHLCV[] {
|
|
114
|
+
return this.context.getMarketData();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get the event point coordinates, snapping to nearest candle OHLC if Ctrl is held.
|
|
119
|
+
* Use this instead of [params.offsetX, params.offsetY] in click/mousemove handlers.
|
|
120
|
+
*/
|
|
121
|
+
protected getPoint(params: any): [number, number] {
|
|
122
|
+
const x = params.offsetX;
|
|
123
|
+
const y = params.offsetY;
|
|
124
|
+
const event = params.event;
|
|
125
|
+
const ctrlKey = event?.ctrlKey || event?.metaKey;
|
|
126
|
+
|
|
127
|
+
if (ctrlKey) {
|
|
128
|
+
const snapped = this.context.snapToCandle({ x, y });
|
|
129
|
+
return [snapped.x, snapped.y];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return [x, y];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --- Snap Indicator (internal) ---
|
|
136
|
+
|
|
137
|
+
private _bindSnapIndicator(): void {
|
|
138
|
+
const zr = this.context.getChart().getZr();
|
|
139
|
+
|
|
140
|
+
this._snapMoveHandler = (e: any) => {
|
|
141
|
+
this._lastMouseEvent = e;
|
|
142
|
+
const ctrlKey = e.event?.ctrlKey || e.event?.metaKey;
|
|
143
|
+
if (ctrlKey) {
|
|
144
|
+
this._showSnapAt(e.offsetX, e.offsetY);
|
|
145
|
+
} else {
|
|
146
|
+
this._hideSnap();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
this._snapKeyDownHandler = (e: KeyboardEvent) => {
|
|
151
|
+
if ((e.key === "Control" || e.key === "Meta") && this._lastMouseEvent) {
|
|
152
|
+
this._showSnapAt(this._lastMouseEvent.offsetX, this._lastMouseEvent.offsetY);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
this._snapKeyUpHandler = (e: KeyboardEvent) => {
|
|
157
|
+
if (e.key === "Control" || e.key === "Meta") {
|
|
158
|
+
this._hideSnap();
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// On Mac, Cmd+Tab can swallow the keyup event — hide snap when window loses focus
|
|
163
|
+
this._snapBlurHandler = () => {
|
|
164
|
+
this._hideSnap();
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
zr.on("mousemove", this._snapMoveHandler);
|
|
168
|
+
window.addEventListener("keydown", this._snapKeyDownHandler);
|
|
169
|
+
window.addEventListener("keyup", this._snapKeyUpHandler);
|
|
170
|
+
window.addEventListener("blur", this._snapBlurHandler);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private _unbindSnapIndicator(): void {
|
|
174
|
+
if (this._snapMoveHandler) {
|
|
175
|
+
try {
|
|
176
|
+
this.context.getChart().getZr().off("mousemove", this._snapMoveHandler);
|
|
177
|
+
} catch {}
|
|
178
|
+
this._snapMoveHandler = null;
|
|
179
|
+
}
|
|
180
|
+
if (this._snapKeyDownHandler) {
|
|
181
|
+
window.removeEventListener("keydown", this._snapKeyDownHandler);
|
|
182
|
+
this._snapKeyDownHandler = null;
|
|
183
|
+
}
|
|
184
|
+
if (this._snapKeyUpHandler) {
|
|
185
|
+
window.removeEventListener("keyup", this._snapKeyUpHandler);
|
|
186
|
+
this._snapKeyUpHandler = null;
|
|
187
|
+
}
|
|
188
|
+
if (this._snapBlurHandler) {
|
|
189
|
+
window.removeEventListener("blur", this._snapBlurHandler);
|
|
190
|
+
this._snapBlurHandler = null;
|
|
191
|
+
}
|
|
192
|
+
this._removeSnapGraphic();
|
|
193
|
+
this._lastMouseEvent = null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private _removeSnapGraphic(): void {
|
|
197
|
+
if (this._snapIndicator) {
|
|
198
|
+
try {
|
|
199
|
+
this.context.getChart().getZr().remove(this._snapIndicator);
|
|
200
|
+
} catch {}
|
|
201
|
+
this._snapIndicator = null;
|
|
202
|
+
this._snapActive = false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private _showSnapAt(x: number, y: number): void {
|
|
207
|
+
const snapped = this.context.snapToCandle({ x, y });
|
|
208
|
+
const zr = this.context.getChart().getZr();
|
|
209
|
+
if (!this._snapIndicator) {
|
|
210
|
+
this._snapIndicator = new echarts.graphic.Circle({
|
|
211
|
+
shape: { cx: 0, cy: 0, r: 5 },
|
|
212
|
+
style: {
|
|
213
|
+
fill: "rgba(59, 130, 246, 0.3)",
|
|
214
|
+
stroke: "#3b82f6",
|
|
215
|
+
lineWidth: 1.5,
|
|
216
|
+
},
|
|
217
|
+
z: 9999,
|
|
218
|
+
silent: true,
|
|
219
|
+
});
|
|
220
|
+
zr.add(this._snapIndicator);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
this._snapIndicator.setShape({ cx: snapped.x, cy: snapped.y });
|
|
224
|
+
this._snapIndicator.show();
|
|
225
|
+
this._snapActive = true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private _hideSnap(): void {
|
|
229
|
+
if (this._snapIndicator && this._snapActive) {
|
|
230
|
+
this._snapIndicator.hide();
|
|
231
|
+
this._snapActive = false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|