@qfo/qfchart 0.8.0 → 0.8.1

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 (50) hide show
  1. package/dist/index.d.ts +319 -12
  2. package/dist/qfchart.min.browser.js +32 -16
  3. package/dist/qfchart.min.es.js +32 -16
  4. package/package.json +1 -1
  5. package/src/QFChart.ts +98 -262
  6. package/src/components/AbstractPlugin.ts +234 -104
  7. package/src/components/DrawingEditor.ts +297 -248
  8. package/src/components/DrawingRendererRegistry.ts +13 -0
  9. package/src/components/GraphicBuilder.ts +2 -2
  10. package/src/components/LayoutManager.ts +41 -35
  11. package/src/components/SeriesBuilder.ts +10 -10
  12. package/src/components/TooltipFormatter.ts +1 -1
  13. package/src/index.ts +17 -6
  14. package/src/plugins/ABCDPatternTool/ABCDPatternDrawingRenderer.ts +112 -0
  15. package/src/plugins/ABCDPatternTool/ABCDPatternTool.ts +136 -0
  16. package/src/plugins/ABCDPatternTool/index.ts +2 -0
  17. package/src/plugins/CypherPatternTool/CypherPatternDrawingRenderer.ts +80 -0
  18. package/src/plugins/CypherPatternTool/CypherPatternTool.ts +84 -0
  19. package/src/plugins/CypherPatternTool/index.ts +2 -0
  20. package/src/plugins/FibSpeedResistanceFanTool/FibSpeedResistanceFanDrawingRenderer.ts +163 -0
  21. package/src/plugins/FibSpeedResistanceFanTool/FibSpeedResistanceFanTool.ts +210 -0
  22. package/src/plugins/FibSpeedResistanceFanTool/index.ts +2 -0
  23. package/src/plugins/FibTrendExtensionTool/FibTrendExtensionDrawingRenderer.ts +141 -0
  24. package/src/plugins/FibTrendExtensionTool/FibTrendExtensionTool.ts +188 -0
  25. package/src/plugins/FibTrendExtensionTool/index.ts +2 -0
  26. package/src/plugins/FibonacciChannelTool/FibonacciChannelDrawingRenderer.ts +128 -0
  27. package/src/plugins/FibonacciChannelTool/FibonacciChannelTool.ts +231 -0
  28. package/src/plugins/FibonacciChannelTool/index.ts +2 -0
  29. package/src/plugins/FibonacciTool/FibonacciDrawingRenderer.ts +107 -0
  30. package/src/plugins/{FibonacciTool.ts → FibonacciTool/FibonacciTool.ts} +195 -192
  31. package/src/plugins/FibonacciTool/index.ts +2 -0
  32. package/src/plugins/HeadAndShouldersTool/HeadAndShouldersDrawingRenderer.ts +95 -0
  33. package/src/plugins/HeadAndShouldersTool/HeadAndShouldersTool.ts +97 -0
  34. package/src/plugins/HeadAndShouldersTool/index.ts +2 -0
  35. package/src/plugins/LineTool/LineDrawingRenderer.ts +49 -0
  36. package/src/plugins/{LineTool.ts → LineTool/LineTool.ts} +161 -190
  37. package/src/plugins/LineTool/index.ts +2 -0
  38. package/src/plugins/{MeasureTool.ts → MeasureTool/MeasureTool.ts} +324 -344
  39. package/src/plugins/MeasureTool/index.ts +1 -0
  40. package/src/plugins/ThreeDrivesPatternTool/ThreeDrivesPatternDrawingRenderer.ts +106 -0
  41. package/src/plugins/ThreeDrivesPatternTool/ThreeDrivesPatternTool.ts +98 -0
  42. package/src/plugins/ThreeDrivesPatternTool/index.ts +2 -0
  43. package/src/plugins/ToolGroup.ts +211 -0
  44. package/src/plugins/TrianglePatternTool/TrianglePatternDrawingRenderer.ts +107 -0
  45. package/src/plugins/TrianglePatternTool/TrianglePatternTool.ts +98 -0
  46. package/src/plugins/TrianglePatternTool/index.ts +2 -0
  47. package/src/plugins/XABCDPatternTool/XABCDPatternDrawingRenderer.ts +178 -0
  48. package/src/plugins/XABCDPatternTool/XABCDPatternTool.ts +213 -0
  49. package/src/plugins/XABCDPatternTool/index.ts +2 -0
  50. package/src/types.ts +37 -11
@@ -1,248 +1,297 @@
1
- import { ChartContext, DrawingElement, DataCoordinate } from "../types";
2
- import * as echarts from "echarts";
3
-
4
- export class DrawingEditor {
5
- private context: ChartContext;
6
- private isEditing: boolean = false;
7
- private currentDrawing: DrawingElement | null = null;
8
- private editingPointIndex: number | null = null;
9
- private zr: any;
10
-
11
- // Temporary ZRender elements for visual feedback during drag
12
- private editGroup: any = null;
13
- private editLine: any = null;
14
- private editStartPoint: any = null;
15
- private editEndPoint: any = null;
16
-
17
- private isMovingShape: boolean = false;
18
- private dragStart: { x: number; y: number } | null = null;
19
- private initialPixelPoints: { x: number; y: number }[] = [];
20
-
21
- constructor(context: ChartContext) {
22
- this.context = context;
23
- this.zr = this.context.getChart().getZr();
24
- this.bindEvents();
25
- }
26
-
27
- private bindEvents() {
28
- this.context.events.on("drawing:point:mousedown", this.onPointMouseDown);
29
- this.context.events.on("drawing:mousedown", this.onDrawingMouseDown);
30
- }
31
-
32
- private onDrawingMouseDown = (payload: {
33
- id: string;
34
- x: number;
35
- y: number;
36
- }) => {
37
- if (this.isEditing) return;
38
-
39
- const drawing = this.context.getDrawing(payload.id);
40
- if (!drawing) return;
41
-
42
- this.isEditing = true;
43
- this.isMovingShape = true;
44
- this.currentDrawing = JSON.parse(JSON.stringify(drawing));
45
- this.dragStart = { x: payload.x, y: payload.y };
46
-
47
- // Capture initial pixel positions
48
- this.initialPixelPoints = drawing.points.map((p) => {
49
- const pixel = this.context.coordinateConversion.dataToPixel(p);
50
- return pixel ? { x: pixel.x, y: pixel.y } : { x: 0, y: 0 }; // Fallback
51
- });
52
-
53
- this.context.lockChart();
54
- this.createEditGraphic();
55
-
56
- this.zr.on("mousemove", this.onMouseMove);
57
- this.zr.on("mouseup", this.onMouseUp);
58
- };
59
-
60
- private onPointMouseDown = (payload: { id: string; pointIndex: number }) => {
61
- if (this.isEditing) return;
62
-
63
- const drawing = this.context.getDrawing(payload.id);
64
- if (!drawing) return;
65
-
66
- // Start Editing
67
- this.isEditing = true;
68
- this.currentDrawing = JSON.parse(JSON.stringify(drawing)); // Deep copy
69
- this.editingPointIndex = payload.pointIndex;
70
-
71
- this.context.lockChart();
72
-
73
- // Create visual feedback (overlay)
74
- this.createEditGraphic();
75
-
76
- // Hide the actual drawing (optional, but good for UX so we don't see double)
77
- // Actually, we can just drag the overlay and update the drawing on mouseup.
78
- // The underlying drawing remains visible but static until updated.
79
-
80
- // Bind temporary drag listeners
81
- this.zr.on("mousemove", this.onMouseMove);
82
- this.zr.on("mouseup", this.onMouseUp);
83
- // Global mouseup to catch releases outside chart area if needed (window listener better?)
84
- // ZRender usually handles global mouseup if initiated within.
85
- };
86
-
87
- private createEditGraphic() {
88
- if (!this.currentDrawing) return;
89
-
90
- this.editGroup = new echarts.graphic.Group();
91
-
92
- // We need current pixel coordinates
93
- const p1Data = this.currentDrawing.points[0];
94
- const p2Data = this.currentDrawing.points[1];
95
-
96
- const p1 = this.context.coordinateConversion.dataToPixel(p1Data);
97
- const p2 = this.context.coordinateConversion.dataToPixel(p2Data);
98
-
99
- if (!p1 || !p2) return;
100
-
101
- // Create Line
102
- this.editLine = new echarts.graphic.Line({
103
- shape: { x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y },
104
- style: {
105
- stroke: this.currentDrawing.style?.color || "#3b82f6",
106
- lineWidth: this.currentDrawing.style?.lineWidth || 2,
107
- lineDash: [4, 4], // Dashed to indicate editing
108
- },
109
- silent: true, // Events pass through to handlers
110
- });
111
-
112
- // Create Points (we only really need to visualize the one being dragged, but showing both is fine)
113
- this.editStartPoint = new echarts.graphic.Circle({
114
- shape: { cx: p1.x, cy: p1.y, r: 5 },
115
- style: { fill: "#fff", stroke: "#3b82f6", lineWidth: 2 },
116
- z: 1000,
117
- });
118
-
119
- this.editEndPoint = new echarts.graphic.Circle({
120
- shape: { cx: p2.x, cy: p2.y, r: 5 },
121
- style: { fill: "#fff", stroke: "#3b82f6", lineWidth: 2 },
122
- z: 1000,
123
- });
124
-
125
- this.editGroup.add(this.editLine);
126
- this.editGroup.add(this.editStartPoint);
127
- this.editGroup.add(this.editEndPoint);
128
-
129
- this.zr.add(this.editGroup);
130
- }
131
-
132
- private onMouseMove = (e: any) => {
133
- if (!this.isEditing || !this.currentDrawing) return;
134
-
135
- const x = e.offsetX;
136
- const y = e.offsetY;
137
-
138
- if (this.isMovingShape && this.dragStart) {
139
- const dx = x - this.dragStart.x;
140
- const dy = y - this.dragStart.y;
141
-
142
- // Apply delta to all points
143
- const newP1 = {
144
- x: this.initialPixelPoints[0].x + dx,
145
- y: this.initialPixelPoints[0].y + dy,
146
- };
147
- const newP2 = {
148
- x: this.initialPixelPoints[1].x + dx,
149
- y: this.initialPixelPoints[1].y + dy,
150
- };
151
-
152
- this.editLine.setShape({
153
- x1: newP1.x,
154
- y1: newP1.y,
155
- x2: newP2.x,
156
- y2: newP2.y,
157
- });
158
- this.editStartPoint.setShape({ cx: newP1.x, cy: newP1.y });
159
- this.editEndPoint.setShape({ cx: newP2.x, cy: newP2.y });
160
- } else if (this.editingPointIndex !== null) {
161
- // Update the pixel position of the edited point in the overlay
162
- if (this.editingPointIndex === 0) {
163
- this.editLine.setShape({ x1: x, y1: y });
164
- this.editStartPoint.setShape({ cx: x, cy: y });
165
- } else {
166
- this.editLine.setShape({ x2: x, y2: y });
167
- this.editEndPoint.setShape({ cx: x, cy: y });
168
- }
169
- }
170
- };
171
-
172
- private onMouseUp = (e: any) => {
173
- if (!this.isEditing) return;
174
-
175
- // Commit changes
176
- this.finishEditing(e.offsetX, e.offsetY);
177
- };
178
-
179
- private finishEditing(finalX: number, finishY: number) {
180
- if (!this.currentDrawing) return;
181
-
182
- if (this.isMovingShape && this.dragStart) {
183
- const dx = finalX - this.dragStart.x;
184
- const dy = finishY - this.dragStart.y;
185
-
186
- // Update all points
187
- const newPoints = this.initialPixelPoints.map((p, i) => {
188
- const newX = p.x + dx;
189
- const newY = p.y + dy;
190
- return this.context.coordinateConversion.pixelToData({
191
- x: newX,
192
- y: newY,
193
- });
194
- });
195
-
196
- // Check if conversion succeeded
197
- if (newPoints.every((p) => p !== null)) {
198
- // Update points
199
- // Assuming 2 points for line tool
200
- if (newPoints[0] && newPoints[1]) {
201
- this.currentDrawing.points[0] = newPoints[0];
202
- this.currentDrawing.points[1] = newPoints[1];
203
-
204
- // Update pane index if we moved significantly (using start point as ref)
205
- if (newPoints[0].paneIndex !== undefined) {
206
- this.currentDrawing.paneIndex = newPoints[0].paneIndex;
207
- }
208
-
209
- this.context.updateDrawing(this.currentDrawing);
210
- }
211
- }
212
- } else if (this.editingPointIndex !== null) {
213
- // Convert final pixel to data
214
- const newData = this.context.coordinateConversion.pixelToData({
215
- x: finalX,
216
- y: finishY,
217
- });
218
-
219
- if (newData) {
220
- this.currentDrawing.points[this.editingPointIndex] = newData;
221
-
222
- if (this.editingPointIndex === 0 && newData.paneIndex !== undefined) {
223
- this.currentDrawing.paneIndex = newData.paneIndex;
224
- }
225
-
226
- this.context.updateDrawing(this.currentDrawing);
227
- }
228
- }
229
-
230
- // Cleanup
231
- this.isEditing = false;
232
- this.isMovingShape = false;
233
- this.dragStart = null;
234
- this.initialPixelPoints = [];
235
- this.currentDrawing = null;
236
- this.editingPointIndex = null;
237
-
238
- if (this.editGroup) {
239
- this.zr.remove(this.editGroup);
240
- this.editGroup = null;
241
- }
242
-
243
- this.zr.off("mousemove", this.onMouseMove);
244
- this.zr.off("mouseup", this.onMouseUp);
245
-
246
- this.context.unlockChart();
247
- }
248
- }
1
+ import { ChartContext, DrawingElement, DataCoordinate } from '../types';
2
+ import * as echarts from 'echarts';
3
+
4
+ export class DrawingEditor {
5
+ private context: ChartContext;
6
+ private isEditing: boolean = false;
7
+ private currentDrawing: DrawingElement | null = null;
8
+ private editingPointIndex: number | null = null;
9
+ private zr: any;
10
+
11
+ // Temporary ZRender elements for visual feedback during drag
12
+ private editGroup: any = null;
13
+ private editLines: any[] = [];
14
+ private editPoints: any[] = [];
15
+
16
+ private isMovingShape: boolean = false;
17
+ private dragStart: { x: number; y: number } | null = null;
18
+ private initialPixelPoints: { x: number; y: number }[] = [];
19
+
20
+ constructor(context: ChartContext) {
21
+ this.context = context;
22
+ this.zr = this.context.getChart().getZr();
23
+ this.bindEvents();
24
+ }
25
+
26
+ private bindEvents() {
27
+ this.context.events.on('drawing:point:mousedown', this.onPointMouseDown);
28
+ this.context.events.on('drawing:mousedown', this.onDrawingMouseDown);
29
+ }
30
+
31
+ private onDrawingMouseDown = (payload: { id: string; x: number; y: number }) => {
32
+ if (this.isEditing) return;
33
+
34
+ const drawing = this.context.getDrawing(payload.id);
35
+ if (!drawing) return;
36
+
37
+ this.isEditing = true;
38
+ this.isMovingShape = true;
39
+ this.currentDrawing = JSON.parse(JSON.stringify(drawing));
40
+ this.dragStart = { x: payload.x, y: payload.y };
41
+
42
+ // Capture initial pixel positions for all points
43
+ this.initialPixelPoints = drawing.points.map((p) => {
44
+ const pixel = this.context.coordinateConversion.dataToPixel(p);
45
+ return pixel ? { x: pixel.x, y: pixel.y } : { x: 0, y: 0 };
46
+ });
47
+
48
+ this.context.lockChart();
49
+ this.createEditGraphic();
50
+
51
+ this.zr.on('mousemove', this.onMouseMove);
52
+ this.zr.on('mouseup', this.onMouseUp);
53
+ // Safety net: catch mouseup outside the canvas
54
+ window.addEventListener('mouseup', this.onWindowMouseUp);
55
+ };
56
+
57
+ private onPointMouseDown = (payload: { id: string; pointIndex: number }) => {
58
+ if (this.isEditing) return;
59
+
60
+ const drawing = this.context.getDrawing(payload.id);
61
+ if (!drawing) return;
62
+
63
+ this.isEditing = true;
64
+ this.currentDrawing = JSON.parse(JSON.stringify(drawing));
65
+ this.editingPointIndex = payload.pointIndex;
66
+
67
+ // Capture initial pixel positions for all points
68
+ this.initialPixelPoints = drawing.points.map((p) => {
69
+ const pixel = this.context.coordinateConversion.dataToPixel(p);
70
+ return pixel ? { x: pixel.x, y: pixel.y } : { x: 0, y: 0 };
71
+ });
72
+
73
+ this.context.lockChart();
74
+ this.createEditGraphic();
75
+
76
+ this.zr.on('mousemove', this.onMouseMove);
77
+ this.zr.on('mouseup', this.onMouseUp);
78
+ // Safety net: catch mouseup outside the canvas
79
+ window.addEventListener('mouseup', this.onWindowMouseUp);
80
+ };
81
+
82
+ private createEditGraphic() {
83
+ if (!this.currentDrawing) return;
84
+
85
+ this.editGroup = new echarts.graphic.Group();
86
+ this.editLines = [];
87
+ this.editPoints = [];
88
+
89
+ const pixelPts = this.currentDrawing.points.map((p) => {
90
+ const px = this.context.coordinateConversion.dataToPixel(p);
91
+ return px ? { x: px.x, y: px.y } : null;
92
+ });
93
+
94
+ if (pixelPts.some((p) => !p)) return;
95
+ const pts = pixelPts as { x: number; y: number }[];
96
+
97
+ // Connect consecutive points with dashed lines
98
+ for (let i = 0; i < pts.length - 1; i++) {
99
+ const line = new echarts.graphic.Line({
100
+ shape: { x1: pts[i].x, y1: pts[i].y, x2: pts[i + 1].x, y2: pts[i + 1].y },
101
+ style: {
102
+ stroke: this.currentDrawing.style?.color || '#3b82f6',
103
+ lineWidth: this.currentDrawing.style?.lineWidth || 2,
104
+ lineDash: [4, 4],
105
+ },
106
+ silent: true,
107
+ });
108
+ this.editLines.push(line);
109
+ this.editGroup.add(line);
110
+ }
111
+
112
+ // Control point circles for each point
113
+ for (let i = 0; i < pts.length; i++) {
114
+ const circle = new echarts.graphic.Circle({
115
+ shape: { cx: pts[i].x, cy: pts[i].y, r: 5 },
116
+ style: { fill: '#fff', stroke: '#3b82f6', lineWidth: 2 },
117
+ z: 1000,
118
+ });
119
+ this.editPoints.push(circle);
120
+ this.editGroup.add(circle);
121
+ }
122
+
123
+ this.zr.add(this.editGroup);
124
+ }
125
+
126
+ private onMouseMove = (e: any) => {
127
+ if (!this.isEditing || !this.currentDrawing) return;
128
+
129
+ const x = e.offsetX;
130
+ const y = e.offsetY;
131
+
132
+ if (this.isMovingShape && this.dragStart) {
133
+ const dx = x - this.dragStart.x;
134
+ const dy = y - this.dragStart.y;
135
+
136
+ // Compute new positions for all points
137
+ const newPts = this.initialPixelPoints.map((p) => ({
138
+ x: p.x + dx,
139
+ y: p.y + dy,
140
+ }));
141
+
142
+ // Update lines
143
+ for (let i = 0; i < this.editLines.length; i++) {
144
+ this.editLines[i].setShape({
145
+ x1: newPts[i].x,
146
+ y1: newPts[i].y,
147
+ x2: newPts[i + 1].x,
148
+ y2: newPts[i + 1].y,
149
+ });
150
+ }
151
+
152
+ // Update point circles
153
+ for (let i = 0; i < this.editPoints.length; i++) {
154
+ this.editPoints[i].setShape({ cx: newPts[i].x, cy: newPts[i].y });
155
+ }
156
+ } else if (this.editingPointIndex !== null) {
157
+ // Compute new positions: only the dragged point moves
158
+ const newPts = this.initialPixelPoints.map((p) => ({ x: p.x, y: p.y }));
159
+ newPts[this.editingPointIndex] = { x, y };
160
+
161
+ // Update lines connected to this point
162
+ for (let i = 0; i < this.editLines.length; i++) {
163
+ this.editLines[i].setShape({
164
+ x1: newPts[i].x,
165
+ y1: newPts[i].y,
166
+ x2: newPts[i + 1].x,
167
+ y2: newPts[i + 1].y,
168
+ });
169
+ }
170
+
171
+ // Update the dragged point circle
172
+ this.editPoints[this.editingPointIndex].setShape({ cx: x, cy: y });
173
+ }
174
+ };
175
+
176
+ private onMouseUp = (e: any) => {
177
+ if (!this.isEditing) return;
178
+ this.finishEditing(e.offsetX, e.offsetY);
179
+ };
180
+
181
+ /**
182
+ * Safety net: catches mouseup when the cursor leaves the canvas area.
183
+ * Uses the last known pixel positions to compute the final drop location
184
+ * relative to the chart container.
185
+ */
186
+ private onWindowMouseUp = (e: MouseEvent) => {
187
+ if (!this.isEditing) return;
188
+
189
+ // Convert page coordinates to offset relative to the chart canvas
190
+ const dom = this.zr.dom as HTMLElement;
191
+ if (dom) {
192
+ const rect = dom.getBoundingClientRect();
193
+ const offsetX = e.clientX - rect.left;
194
+ const offsetY = e.clientY - rect.top;
195
+ this.finishEditing(offsetX, offsetY);
196
+ } else {
197
+ // Fallback: just clean up without committing the move
198
+ this.finishEditing(this.dragStart?.x ?? 0, this.dragStart?.y ?? 0);
199
+ }
200
+ };
201
+
202
+ /**
203
+ * Convert pixel to data, falling back to the drawing's known pane
204
+ * when the point is outside the grid (e.g., dragged beyond viewport).
205
+ * Uses convertFromPixel with the specific gridIndex directly, bypassing
206
+ * the containPixel check that would return null for out-of-bounds points.
207
+ */
208
+ private pixelToDataForPane(x: number, y: number, paneIndex: number): DataCoordinate | null {
209
+ // First try the normal conversion (respects pane boundaries)
210
+ const normal = this.context.coordinateConversion.pixelToData({ x, y });
211
+ if (normal) return normal;
212
+
213
+ // Fallback: force conversion using the drawing's known pane
214
+ try {
215
+ const chart = this.context.getChart();
216
+ const p = chart.convertFromPixel({ gridIndex: paneIndex }, [x, y]);
217
+ if (p) {
218
+ // We need the dataIndexOffset — read from the chart's xAxis data length
219
+ const option = chart.getOption() as any;
220
+ const xAxisData = option?.xAxis?.[paneIndex]?.data;
221
+ const marketData = this.context.getMarketData();
222
+ const dataIndexOffset = xAxisData ? Math.round((xAxisData.length - marketData.length) / 2) : 0;
223
+ return { timeIndex: Math.round(p[0]) - dataIndexOffset, value: p[1], paneIndex };
224
+ }
225
+ } catch (_) {
226
+ // Ignore conversion errors
227
+ }
228
+ return null;
229
+ }
230
+
231
+ private finishEditing(finalX: number, finalY: number) {
232
+ if (!this.currentDrawing) {
233
+ this.cleanup();
234
+ return;
235
+ }
236
+
237
+ const paneIndex = this.currentDrawing.paneIndex || 0;
238
+
239
+ if (this.isMovingShape && this.dragStart) {
240
+ const dx = finalX - this.dragStart.x;
241
+ const dy = finalY - this.dragStart.y;
242
+
243
+ // Update all points using pane-aware conversion
244
+ const newPoints = this.initialPixelPoints.map((p) =>
245
+ this.pixelToDataForPane(p.x + dx, p.y + dy, paneIndex),
246
+ );
247
+
248
+ if (newPoints.every((p) => p !== null)) {
249
+ for (let i = 0; i < newPoints.length; i++) {
250
+ this.currentDrawing.points[i] = newPoints[i]!;
251
+ }
252
+
253
+ if (newPoints[0]?.paneIndex !== undefined) {
254
+ this.currentDrawing.paneIndex = newPoints[0].paneIndex;
255
+ }
256
+
257
+ this.context.updateDrawing(this.currentDrawing);
258
+ }
259
+ } else if (this.editingPointIndex !== null) {
260
+ const newData = this.pixelToDataForPane(finalX, finalY, paneIndex);
261
+
262
+ if (newData) {
263
+ this.currentDrawing.points[this.editingPointIndex] = newData;
264
+
265
+ if (this.editingPointIndex === 0 && newData.paneIndex !== undefined) {
266
+ this.currentDrawing.paneIndex = newData.paneIndex;
267
+ }
268
+
269
+ this.context.updateDrawing(this.currentDrawing);
270
+ }
271
+ }
272
+
273
+ this.cleanup();
274
+ }
275
+
276
+ private cleanup() {
277
+ this.isEditing = false;
278
+ this.isMovingShape = false;
279
+ this.dragStart = null;
280
+ this.initialPixelPoints = [];
281
+ this.currentDrawing = null;
282
+ this.editingPointIndex = null;
283
+ this.editLines = [];
284
+ this.editPoints = [];
285
+
286
+ if (this.editGroup) {
287
+ this.zr.remove(this.editGroup);
288
+ this.editGroup = null;
289
+ }
290
+
291
+ this.zr.off('mousemove', this.onMouseMove);
292
+ this.zr.off('mouseup', this.onMouseUp);
293
+ window.removeEventListener('mouseup', this.onWindowMouseUp);
294
+
295
+ this.context.unlockChart();
296
+ }
297
+ }
@@ -0,0 +1,13 @@
1
+ import { DrawingRenderer } from '../types';
2
+
3
+ export class DrawingRendererRegistry {
4
+ private renderers = new Map<string, DrawingRenderer>();
5
+
6
+ register(renderer: DrawingRenderer): void {
7
+ this.renderers.set(renderer.type, renderer);
8
+ }
9
+
10
+ get(type: string): DrawingRenderer | undefined {
11
+ return this.renderers.get(type);
12
+ }
13
+ }
@@ -8,7 +8,7 @@ export class GraphicBuilder {
8
8
  onToggle: (id: string, action?: 'collapse' | 'maximize' | 'fullscreen') => void,
9
9
  isMainCollapsed: boolean = false,
10
10
  maximizedPaneId: string | null = null,
11
- overlayIndicators: { id: string; titleColor?: string }[] = []
11
+ overlayIndicators: { id: string; titleColor?: string }[] = [],
12
12
  ): any[] {
13
13
  const graphic: any[] = [];
14
14
  const pixelToPercent = layout.pixelToPercent;
@@ -29,7 +29,7 @@ export class GraphicBuilder {
29
29
  top: mainPaneTop + titleTopMargin + '%',
30
30
  z: 10,
31
31
  style: {
32
- text: options.title || 'Market',
32
+ text: options.title || '',
33
33
  fill: options.titleColor || '#fff',
34
34
  font: `bold 16px ${options.fontFamily || 'sans-serif'}`,
35
35
  textVerticalAlign: 'top',