@qfo/qfchart 0.8.1 → 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 +206 -1
- package/dist/qfchart.min.browser.js +16 -16
- package/dist/qfchart.min.es.js +16 -16
- package/package.json +1 -1
- package/src/QFChart.ts +11 -10
- package/src/components/LayoutManager.ts +51 -17
- package/src/index.ts +8 -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/ExtendedLineTool/ExtendedLineDrawingRenderer.ts +73 -0
- package/src/plugins/ExtendedLineTool/ExtendedLineTool.ts +173 -0
- package/src/plugins/ExtendedLineTool/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 +2 -2
- package/src/plugins/LineTool/LineTool.ts +5 -5
- 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/TrendAngleTool/TrendAngleDrawingRenderer.ts +87 -0
- package/src/plugins/TrendAngleTool/TrendAngleTool.ts +176 -0
- package/src/plugins/TrendAngleTool/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/types.ts +2 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { AbstractPlugin } from '../../components/AbstractPlugin';
|
|
2
|
+
import { TrendAngleDrawingRenderer } from './TrendAngleDrawingRenderer';
|
|
3
|
+
import * as echarts from 'echarts';
|
|
4
|
+
|
|
5
|
+
const COLOR = '#d1d4dc';
|
|
6
|
+
|
|
7
|
+
type PluginState = 'idle' | 'drawing' | 'finished';
|
|
8
|
+
|
|
9
|
+
export class TrendAngleTool extends AbstractPlugin {
|
|
10
|
+
private zr!: any;
|
|
11
|
+
private state: PluginState = 'idle';
|
|
12
|
+
private startPoint: number[] | null = null;
|
|
13
|
+
private endPoint: number[] | null = null;
|
|
14
|
+
private group: any = null;
|
|
15
|
+
private line: any = null;
|
|
16
|
+
private hRefLine: any = null;
|
|
17
|
+
private arc: any = null;
|
|
18
|
+
private angleText: any = null;
|
|
19
|
+
private startCircle: any = null;
|
|
20
|
+
private endCircle: any = null;
|
|
21
|
+
|
|
22
|
+
constructor(options: { name?: string; icon?: string } = {}) {
|
|
23
|
+
super({
|
|
24
|
+
id: 'trend-angle-tool',
|
|
25
|
+
name: options?.name || 'Trend Angle',
|
|
26
|
+
icon: options?.icon || `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="20" x2="21" y2="6"/><line x1="3" y1="20" x2="14" y2="20" opacity="0.4"/><path d="M8 20 A5 5 0 0 1 7 16" stroke-width="1.5"/></svg>`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected onInit(): void {
|
|
31
|
+
this.zr = this.chart.getZr();
|
|
32
|
+
this.context.registerDrawingRenderer(new TrendAngleDrawingRenderer());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected onActivate(): void {
|
|
36
|
+
this.state = 'idle';
|
|
37
|
+
this.chart.getZr().setCursorStyle('crosshair');
|
|
38
|
+
this.zr.on('click', this.onClick);
|
|
39
|
+
this.zr.on('mousemove', this.onMouseMove);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected onDeactivate(): void {
|
|
43
|
+
this.state = 'idle';
|
|
44
|
+
this.chart.getZr().setCursorStyle('default');
|
|
45
|
+
this.zr.off('click', this.onClick);
|
|
46
|
+
this.zr.off('mousemove', this.onMouseMove);
|
|
47
|
+
this.removeGraphic();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected onDestroy(): void {
|
|
51
|
+
this.removeGraphic();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private onClick = (params: any) => {
|
|
55
|
+
if (this.state === 'idle') {
|
|
56
|
+
this.state = 'drawing';
|
|
57
|
+
this.startPoint = this.getPoint(params);
|
|
58
|
+
this.endPoint = this.getPoint(params);
|
|
59
|
+
this.initGraphic();
|
|
60
|
+
this.updateGraphic();
|
|
61
|
+
} else if (this.state === 'drawing') {
|
|
62
|
+
this.state = 'finished';
|
|
63
|
+
this.endPoint = this.getPoint(params);
|
|
64
|
+
|
|
65
|
+
if (this.startPoint && this.endPoint) {
|
|
66
|
+
const start = this.context.coordinateConversion.pixelToData({
|
|
67
|
+
x: this.startPoint[0], y: this.startPoint[1],
|
|
68
|
+
});
|
|
69
|
+
const end = this.context.coordinateConversion.pixelToData({
|
|
70
|
+
x: this.endPoint[0], y: this.endPoint[1],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (start && end) {
|
|
74
|
+
this.context.addDrawing({
|
|
75
|
+
id: `trend-angle-${Date.now()}`,
|
|
76
|
+
type: 'trend-angle',
|
|
77
|
+
points: [start, end],
|
|
78
|
+
paneIndex: start.paneIndex || 0,
|
|
79
|
+
style: { color: COLOR, lineWidth: 1 },
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.removeGraphic();
|
|
85
|
+
this.context.disableTools();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
private onMouseMove = (params: any) => {
|
|
90
|
+
if (this.state !== 'drawing') return;
|
|
91
|
+
this.endPoint = this.getPoint(params);
|
|
92
|
+
this.updateGraphic();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
private initGraphic(): void {
|
|
96
|
+
if (this.group) return;
|
|
97
|
+
this.group = new echarts.graphic.Group();
|
|
98
|
+
this.line = new echarts.graphic.Line({
|
|
99
|
+
shape: { x1: 0, y1: 0, x2: 0, y2: 0 },
|
|
100
|
+
style: { stroke: COLOR, lineWidth: 1 },
|
|
101
|
+
z: 100,
|
|
102
|
+
});
|
|
103
|
+
this.hRefLine = new echarts.graphic.Line({
|
|
104
|
+
shape: { x1: 0, y1: 0, x2: 0, y2: 0 },
|
|
105
|
+
style: { stroke: COLOR, lineWidth: 1, lineDash: [4, 4], opacity: 0.4 },
|
|
106
|
+
z: 99,
|
|
107
|
+
});
|
|
108
|
+
this.arc = new echarts.graphic.Arc({
|
|
109
|
+
shape: { cx: 0, cy: 0, r: 25, startAngle: 0, endAngle: 0 },
|
|
110
|
+
style: { stroke: COLOR, lineWidth: 1, fill: 'none' },
|
|
111
|
+
z: 99,
|
|
112
|
+
});
|
|
113
|
+
this.angleText = new echarts.graphic.Text({
|
|
114
|
+
style: { text: '', fill: COLOR, fontSize: 11, fontFamily: 'sans-serif' },
|
|
115
|
+
z: 101,
|
|
116
|
+
});
|
|
117
|
+
this.startCircle = new echarts.graphic.Circle({
|
|
118
|
+
shape: { cx: 0, cy: 0, r: 4 },
|
|
119
|
+
style: { fill: '#fff', stroke: COLOR, lineWidth: 1 },
|
|
120
|
+
z: 101,
|
|
121
|
+
});
|
|
122
|
+
this.endCircle = new echarts.graphic.Circle({
|
|
123
|
+
shape: { cx: 0, cy: 0, r: 4 },
|
|
124
|
+
style: { fill: '#fff', stroke: COLOR, lineWidth: 1 },
|
|
125
|
+
z: 101,
|
|
126
|
+
});
|
|
127
|
+
this.group.add(this.hRefLine);
|
|
128
|
+
this.group.add(this.arc);
|
|
129
|
+
this.group.add(this.line);
|
|
130
|
+
this.group.add(this.angleText);
|
|
131
|
+
this.group.add(this.startCircle);
|
|
132
|
+
this.group.add(this.endCircle);
|
|
133
|
+
this.zr.add(this.group);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private removeGraphic(): void {
|
|
137
|
+
if (this.group) {
|
|
138
|
+
this.zr.remove(this.group);
|
|
139
|
+
this.group = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private updateGraphic(): void {
|
|
144
|
+
if (!this.startPoint || !this.endPoint || !this.group) return;
|
|
145
|
+
const [x1, y1] = this.startPoint;
|
|
146
|
+
const [x2, y2] = this.endPoint;
|
|
147
|
+
|
|
148
|
+
this.line.setShape({ x1, y1, x2, y2 });
|
|
149
|
+
this.startCircle.setShape({ cx: x1, cy: y1 });
|
|
150
|
+
this.endCircle.setShape({ cx: x2, cy: y2 });
|
|
151
|
+
|
|
152
|
+
const dx = x2 - x1;
|
|
153
|
+
const dy = y2 - y1;
|
|
154
|
+
|
|
155
|
+
// Horizontal reference from p1
|
|
156
|
+
const hLen = Math.max(Math.abs(dx), 40);
|
|
157
|
+
this.hRefLine.setShape({ x1, y1, x2: x1 + hLen, y2: y1 });
|
|
158
|
+
|
|
159
|
+
// Angle (negate dy for natural angle since screen Y is inverted)
|
|
160
|
+
const angleRad = Math.atan2(-dy, dx);
|
|
161
|
+
const angleDeg = angleRad * (180 / Math.PI);
|
|
162
|
+
const arcR = Math.min(25, Math.sqrt(dx * dx + dy * dy) * 0.3);
|
|
163
|
+
|
|
164
|
+
// Arc from 0 (horizontal) to the line angle
|
|
165
|
+
const screenAngle = Math.atan2(dy, dx); // screen-space angle
|
|
166
|
+
const arcStart = Math.min(0, screenAngle);
|
|
167
|
+
const arcEnd = Math.max(0, screenAngle);
|
|
168
|
+
this.arc.setShape({ cx: x1, cy: y1, r: arcR, startAngle: arcStart, endAngle: arcEnd });
|
|
169
|
+
|
|
170
|
+
// Angle label
|
|
171
|
+
this.angleText.setStyle({ text: `${angleDeg.toFixed(1)}\u00B0` });
|
|
172
|
+
this.angleText.x = x1 + arcR + 6;
|
|
173
|
+
this.angleText.y = y1 + (dy < 0 ? -14 : 2);
|
|
174
|
+
this.angleText.markRedraw();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { DrawingRenderer, DrawingRenderContext } from '../../types';
|
|
2
|
+
|
|
3
|
+
export class VerticalLineDrawingRenderer implements DrawingRenderer {
|
|
4
|
+
type = 'vertical-line';
|
|
5
|
+
|
|
6
|
+
render(ctx: DrawingRenderContext): any {
|
|
7
|
+
const { drawing, pixelPoints, isSelected, coordSys } = ctx;
|
|
8
|
+
const [px, py] = pixelPoints[0];
|
|
9
|
+
const color = drawing.style?.color || '#d1d4dc';
|
|
10
|
+
|
|
11
|
+
const top = coordSys.y;
|
|
12
|
+
const bottom = coordSys.y + coordSys.height;
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
type: 'group',
|
|
16
|
+
children: [
|
|
17
|
+
{
|
|
18
|
+
type: 'line',
|
|
19
|
+
name: 'line',
|
|
20
|
+
shape: { x1: px, y1: top, x2: px, y2: bottom },
|
|
21
|
+
style: {
|
|
22
|
+
stroke: color,
|
|
23
|
+
lineWidth: drawing.style?.lineWidth || 1,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'circle',
|
|
28
|
+
name: 'point-0',
|
|
29
|
+
shape: { cx: px, cy: py, r: 4 },
|
|
30
|
+
style: { fill: '#fff', stroke: color, lineWidth: 1, opacity: isSelected ? 1 : 0 },
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AbstractPlugin } from '../../components/AbstractPlugin';
|
|
2
|
+
import { VerticalLineDrawingRenderer } from './VerticalLineDrawingRenderer';
|
|
3
|
+
|
|
4
|
+
export class VerticalLineTool extends AbstractPlugin {
|
|
5
|
+
private zr!: any;
|
|
6
|
+
|
|
7
|
+
constructor(options: { name?: string; icon?: string } = {}) {
|
|
8
|
+
super({
|
|
9
|
+
id: 'vertical-line-tool',
|
|
10
|
+
name: options?.name || 'Vertical Line',
|
|
11
|
+
icon: options?.icon || `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="2" x2="12" y2="22"/><circle cx="12" cy="12" r="2" fill="currentColor"/></svg>`,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected onInit(): void {
|
|
16
|
+
this.zr = this.chart.getZr();
|
|
17
|
+
this.context.registerDrawingRenderer(new VerticalLineDrawingRenderer());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected onActivate(): void {
|
|
21
|
+
this.chart.getZr().setCursorStyle('crosshair');
|
|
22
|
+
this.zr.on('click', this.onClick);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
protected onDeactivate(): void {
|
|
26
|
+
this.chart.getZr().setCursorStyle('default');
|
|
27
|
+
this.zr.off('click', this.onClick);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected onDestroy(): void {}
|
|
31
|
+
|
|
32
|
+
private onClick = (params: any) => {
|
|
33
|
+
const point = this.getPoint(params);
|
|
34
|
+
if (!point) return;
|
|
35
|
+
|
|
36
|
+
const data = this.context.coordinateConversion.pixelToData({
|
|
37
|
+
x: point[0], y: point[1],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (data) {
|
|
41
|
+
this.context.addDrawing({
|
|
42
|
+
id: `vline-${Date.now()}`,
|
|
43
|
+
type: 'vertical-line',
|
|
44
|
+
points: [data],
|
|
45
|
+
paneIndex: data.paneIndex || 0,
|
|
46
|
+
style: { color: '#d1d4dc', lineWidth: 1 },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.context.disableTools();
|
|
51
|
+
};
|
|
52
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -208,6 +208,8 @@ export interface DrawingRenderContext {
|
|
|
208
208
|
isSelected: boolean;
|
|
209
209
|
/** The ECharts custom series api object */
|
|
210
210
|
api: any;
|
|
211
|
+
/** Grid coordinate system bounds (x, y, width, height in pixels) */
|
|
212
|
+
coordSys: { x: number; y: number; width: number; height: number };
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
export interface DrawingRenderer {
|