st-comp 0.0.146 → 0.0.147

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 (148) hide show
  1. package/components.d.ts +0 -3
  2. package/es/ChartLayout.cjs +1 -1
  3. package/es/ChartLayout.js +2 -2
  4. package/es/Dialog.cjs +1 -1
  5. package/es/Dialog.js +22 -26
  6. package/es/FactorWarning.cjs +1 -1
  7. package/es/FactorWarning.js +103 -112
  8. package/es/KlineBasic.cjs +1 -1
  9. package/es/KlineBasic.js +1426 -671
  10. package/es/KlineNew.cjs +3 -1
  11. package/es/KlineNew.js +2736 -314
  12. package/es/Pagination.cjs +1 -1
  13. package/es/Pagination.js +96 -102
  14. package/es/Table.cjs +1 -1
  15. package/es/Table.js +60 -66
  16. package/es/User.cjs +1 -1
  17. package/es/User.js +96 -103
  18. package/es/VarietySearch.cjs +1 -1
  19. package/es/VarietySearch.js +32 -41
  20. package/es/VirtualTable.cjs +1 -13
  21. package/es/VirtualTable.js +1 -2801
  22. package/es/_initCloneObject-7493ecd5.cjs +1 -0
  23. package/es/{_initCloneObject-14b53c6f.js → _initCloneObject-a8dcd058.js} +26 -26
  24. package/es/{base-ec05f348.cjs → base-00ce90ec.cjs} +3 -3
  25. package/es/{base-437d17f3.js → base-674a354a.js} +63 -64
  26. package/es/config-provider-419ffbf2.js +120 -0
  27. package/es/config-provider-68414290.cjs +3 -0
  28. package/es/dropdown-127a8c0d.cjs +1 -0
  29. package/es/{dropdown-634b5e27.js → dropdown-ce30ada6.js} +30 -31
  30. package/es/el-button-7b9f5933.js +745 -0
  31. package/es/el-button-c00975e1.cjs +1 -0
  32. package/es/{el-checkbox-group-e8fece80.js → el-checkbox-group-0554b352.js} +10 -10
  33. package/es/el-checkbox-group-7a313d34.cjs +1 -0
  34. package/es/{el-empty-bacc6613.js → el-empty-39b3aed7.js} +5 -5
  35. package/es/{el-empty-19ea04f4.cjs → el-empty-87154b6d.cjs} +1 -1
  36. package/es/el-form-item-7867f64d.cjs +12 -0
  37. package/es/{el-form-item-af1855f0.js → el-form-item-fc6f80ab.js} +78 -79
  38. package/es/el-input-2ff1628c.cjs +1 -0
  39. package/es/{el-input-4961b99f.js → el-input-d249ac86.js} +82 -84
  40. package/es/{el-input-number-610fc8ba.js → el-input-number-2066fbb7.js} +35 -36
  41. package/es/el-input-number-d6801a5c.cjs +1 -0
  42. package/es/{el-message-c3b3ac96.js → el-message-9859835d.js} +79 -81
  43. package/es/el-message-ffcf690c.cjs +1 -0
  44. package/es/el-overlay-91784be2.cjs +1 -0
  45. package/es/el-overlay-f0757cc4.js +525 -0
  46. package/es/el-popover-4db657e2.cjs +1 -0
  47. package/es/{el-popover-0aa071f2.js → el-popover-b7b43c1f.js} +18 -18
  48. package/es/el-scrollbar-35bac6b3.js +2452 -0
  49. package/es/el-scrollbar-ec09bbd3.cjs +1 -0
  50. package/es/el-select-0785c35a.cjs +1 -0
  51. package/es/{el-select-9381b156.js → el-select-bcbb7e55.js} +329 -333
  52. package/es/el-table-column-2478adf8.cjs +14 -0
  53. package/es/{el-table-column-55bffba5.js → el-table-column-c1e1a206.js} +346 -350
  54. package/es/el-tag-13ee17b3.cjs +1 -0
  55. package/es/el-tag-73372c6c.js +359 -0
  56. package/es/index-07b61d12.cjs +1 -0
  57. package/es/{index-39ec9741.js → index-45de4a12.js} +7 -7
  58. package/es/index-65b719a4.cjs +1 -0
  59. package/es/index-8b5fbc11.js +66 -0
  60. package/es/index-8c85d7c5.js +858 -0
  61. package/es/index-a49f4743.cjs +2 -0
  62. package/es/{scroll-387fcfdb.js → scroll-cb696ed2.js} +1 -1
  63. package/es/{scroll-41224831.cjs → scroll-cca17da0.cjs} +1 -1
  64. package/es/style.css +1 -1
  65. package/es/{zh-cn-ab9a583d.cjs → zh-cn-37af467d.cjs} +1 -1
  66. package/es/{zh-cn-eb9c2820.js → zh-cn-ef7d7220.js} +2 -2
  67. package/lib/bundle.js +1 -1
  68. package/lib/bundle.umd.cjs +206 -206
  69. package/lib/{index-9b8ff62a.js → index-24f8572c.js} +31450 -33319
  70. package/lib/{python-a9c3d9e5.js → python-2143eee4.js} +1 -1
  71. package/lib/style.css +1 -1
  72. package/package.json +1 -1
  73. package/packages/KlineBasic/components/KlineSub/index.vue +17 -3
  74. package/packages/KlineBasic/index.vue +2 -1
  75. package/packages/KlineBasic/utils.js +20 -2
  76. package/packages/index.ts +0 -2
  77. package/src/pages/KlineBasic/api.js +1 -1
  78. package/src/router/routes.ts +0 -5
  79. package/es/Kline.cjs +0 -1
  80. package/es/Kline.js +0 -1901
  81. package/es/_initCloneObject-441db749.cjs +0 -1
  82. package/es/castArray-4251bbe4.js +0 -10
  83. package/es/castArray-a45823fe.cjs +0 -1
  84. package/es/config-provider-55482a43.js +0 -47
  85. package/es/config-provider-7cdfca4d.cjs +0 -1
  86. package/es/debounce-ac30be50.js +0 -83
  87. package/es/debounce-b2ff12bd.cjs +0 -1
  88. package/es/dropdown-d7c59a21.cjs +0 -1
  89. package/es/el-button-196807af.cjs +0 -1
  90. package/es/el-button-e1665717.js +0 -235
  91. package/es/el-checkbox-group-492b95cc.cjs +0 -1
  92. package/es/el-form-item-5bdffd07.cjs +0 -12
  93. package/es/el-input-23e2bac3.cjs +0 -1
  94. package/es/el-input-number-40a81eb5.cjs +0 -1
  95. package/es/el-menu-item-78b858f2.cjs +0 -1
  96. package/es/el-menu-item-7d04c11a.js +0 -771
  97. package/es/el-message-d4df8136.cjs +0 -1
  98. package/es/el-overlay-12dd9b35.js +0 -519
  99. package/es/el-overlay-bc0790a2.cjs +0 -1
  100. package/es/el-popover-8a77e015.cjs +0 -1
  101. package/es/el-popper-50100766.js +0 -2262
  102. package/es/el-popper-746070ba.cjs +0 -1
  103. package/es/el-scrollbar-562d0595.js +0 -201
  104. package/es/el-scrollbar-d1c3e7f7.cjs +0 -1
  105. package/es/el-select-b162dffc.cjs +0 -1
  106. package/es/el-table-column-6d761fce.cjs +0 -14
  107. package/es/el-tag-985d9aff.js +0 -279
  108. package/es/el-tag-c51a6490.cjs +0 -1
  109. package/es/index-09e01b1d.js +0 -81
  110. package/es/index-0cb48e01.js +0 -306
  111. package/es/index-3bf8d597.cjs +0 -1
  112. package/es/index-657047bb.js +0 -513
  113. package/es/index-8a0b1c53.cjs +0 -3
  114. package/es/index-a387515d.cjs +0 -1
  115. package/es/index-a902a0d9.js +0 -59
  116. package/es/index-deb8de52.cjs +0 -1
  117. package/es/index-eea0bcb3.cjs +0 -1
  118. package/es/index.esm-8d9a2abe.js +0 -2432
  119. package/es/index.esm-94a95a2a.cjs +0 -3
  120. package/es/raf-8fc301fd.cjs +0 -1
  121. package/es/raf-b128c7b7.js +0 -6
  122. package/es/typescript-7ae59c4c.js +0 -4
  123. package/es/typescript-b63f8e83.cjs +0 -1
  124. package/es/use-form-common-props-1b84d8f4.cjs +0 -2
  125. package/es/use-form-common-props-f377e500.js +0 -587
  126. package/es/vnode-7dfd4ed5.js +0 -14
  127. package/es/vnode-7fbc61e1.cjs +0 -1
  128. package/packages/Kline/components/Contextmenu/index.vue +0 -110
  129. package/packages/Kline/components/Tips/index.vue +0 -40
  130. package/packages/Kline/componentsNew/KlineSlide/index.vue +0 -155
  131. package/packages/Kline/componentsNew/KlineSub/index.vue +0 -297
  132. package/packages/Kline/componentsNew/KlineTips/index.vue +0 -66
  133. package/packages/Kline/componentsNew/KlineUtils/index.vue +0 -84
  134. package/packages/Kline/componentsNew/Tips/index.vue +0 -33
  135. package/packages/Kline/formatKlineData.ts +0 -109
  136. package/packages/Kline/images/buy.svg +0 -1
  137. package/packages/Kline/images/pen.png +0 -0
  138. package/packages/Kline/images/sell.svg +0 -1
  139. package/packages/Kline/images/t.svg +0 -1
  140. package/packages/Kline/index.ts +0 -16
  141. package/packages/Kline/index.vue +0 -891
  142. package/packages/Kline/option.ts +0 -539
  143. package/packages/Kline/type.d.ts +0 -219
  144. package/packages/Kline/utils.ts +0 -682
  145. package/src/pages/Kline/api.ts +0 -127
  146. package/src/pages/Kline/components/MultiCycleSingleVariety.vue +0 -701
  147. package/src/pages/Kline/components/SingleCycleSingleVariety.vue +0 -924
  148. package/src/pages/Kline/index.vue +0 -90
@@ -1,891 +0,0 @@
1
- <script setup lang="ts">
2
- import * as echarts from "echarts";
3
- import { ref, computed, watch, onMounted, onUnmounted } from "vue";
4
- import Tips from "./components/Tips/index.vue";
5
- import Contextmenu from "./components/Contextmenu/index.vue";
6
- import { getOption, getLineOption } from "./option";
7
- import { printConsole, formatValue, formatPrice } from "./utils";
8
- import type { EChartsType, EChartsOption, ECElementEvent, DataZoomComponentOption } from "echarts";
9
- import type { KlineDataType, LineDataType, InConfig, MenuDataType } from "./type.d.ts";
10
-
11
- /**
12
- * 组件接收参数
13
- * @param {Object} indicator 指标线
14
- * @param {KlineDataType} klineData K线数据
15
- * @param {Array} markData 标注点位数据 [开平点, 买卖点, 信号点,...]
16
- * @param {Array} lineData K线额外画线数据 [预警线, 持仓线, 条件单, ...]
17
- * @param {Array} brushRange 区域刷选范围数据
18
- * @param {Array} defaultMenuData 菜单项数据
19
- * @param {Boolean} isSelect 组件是否被选中
20
- *
21
- * @param {InConfig} config 其他配置项数据
22
- */
23
- const props = defineProps({
24
- indicator: {
25
- type: Object,
26
- default: () => ({}),
27
- },
28
- klineData: {
29
- type: Array,
30
- default: () => [],
31
- },
32
- markData: {
33
- type: Array,
34
- default: () => [],
35
- },
36
- lineData: {
37
- type: Array,
38
- default: () => [],
39
- },
40
- netPositionData: {
41
- type: Array,
42
- default: () => [],
43
- },
44
- relevanceData: {
45
- type: Array,
46
- default: () => [],
47
- },
48
- priceTrendData: {
49
- type: Array,
50
- default: () => [],
51
- },
52
- priceTrendPercentData: {
53
- type: Array,
54
- default: () => [],
55
- },
56
- brushRange: {
57
- type: Array,
58
- default: () => [],
59
- },
60
- defaultMenuData: {
61
- type: Array,
62
- default: () => [],
63
- },
64
- isSelect: {
65
- type: Boolean,
66
- default: () => false,
67
- },
68
- config: {
69
- type: Object,
70
- default: () => ({}),
71
- },
72
- });
73
-
74
- /**
75
- * K线功能默认配置
76
- * @param {Number} totalBarCount k线总条数
77
- * @param {Number} defaultShowBarCount k线默认展示条数
78
- * @param {Number} preBarCount k线预加载条数,用于计算指标线
79
- * ---------------------------------------------------------
80
- * @param {Number} gridLeft k线组件grid: left
81
- * @param {Number} gridTop k线组件grid: top
82
- * @param {Number} gridRight k线组件grid: right
83
- * @param {Number} gridBottom k线组件grid: bottom
84
- * ---------------------------------------------------------
85
- * @param {Object} warningConfig 预警线配置
86
- * @param {Object} positionConfig 持仓线配置
87
- * @param {Object} conditionConfig 条件单配置
88
- */
89
- const defaultConfig: InConfig = {
90
- totalBarCount: 2000,
91
- defaultShowBarCount: 200,
92
- preBarCount: 800,
93
- maxValueSpan: 10000,
94
- gridLeft: 60,
95
- gridTop: 0,
96
- gridRight: 60,
97
- gridBottom: 30,
98
- // 预警线配置
99
- warningConfig: {
100
- draggable: false,
101
- lineColor: "#fff",
102
- textColor: "#fff",
103
- },
104
- // 持仓线配置
105
- positionConfig: {
106
- draggable: false,
107
- lineColor: "#e45d07",
108
- textColor: "#fff",
109
- },
110
- // 条件单配置
111
- conditionConfig: {
112
- draggable: false,
113
- lineColor: "#fff",
114
- textColor: "#fff",
115
- profitLineColor: "#b71e44",
116
- profitTextColor: "#fff",
117
- lossLineColor: "#749b66",
118
- lossTextColor: "#fff",
119
- },
120
- // Tips配置
121
- tipsConfig: {
122
- open: true,
123
- heigh: true,
124
- low: true,
125
- close: true,
126
- business: true,
127
- riseAndFall: true,
128
- },
129
- // 动态加载配置
130
- dynamicLoadConfig: {
131
- historyVisible: false,
132
- historyLoadCallBack: () => {},
133
- futureVisible: false,
134
- futureLoadCallBack: () => {},
135
- },
136
- // 是否禁用鼠标滚轮缩放K线,在开启动态后续数据加载时,建议开启,否则会引起datazoom内部缩放拖拽触发后续加载冲突
137
- zoomLock: false,
138
- // 是否启用计算收盘价分布统计功能
139
- isOpenDS: false,
140
- };
141
-
142
- /**
143
- * @description: 合并后的功能配置项
144
- */
145
- const config: { value: InConfig } = computed(() => {
146
- return { ...defaultConfig, ...props.config };
147
- });
148
-
149
- const option = ref<any>(null); // 处理后的echarts配置
150
- const activeIndex = ref(-1); // 当前鼠标激活的数据索引
151
-
152
- // Tips: [开, 收, 低, 高, 成交额, 昨收]
153
- const kLineTips = computed(() => {
154
- if (option.value && option.value.dataset[0]?.source?.klineData[activeIndex.value]) {
155
- const klineItem = option.value.dataset[0].source.klineData[activeIndex.value];
156
- // 处理结果
157
- const result = [];
158
- const { open, heigh, low, close, business, riseAndFall } = config.value.tipsConfig;
159
- open && result.push({ label: "开", value: formatValue(klineItem[0]), color: "rgb(153, 153, 153)" });
160
- heigh && result.push({ label: "高", value: formatValue(klineItem[3]), color: "rgb(153, 153, 153)" });
161
- low && result.push({ label: "低", value: formatValue(klineItem[2]), color: "rgb(153, 153, 153)" });
162
- close && result.push({ label: "收", value: formatValue(klineItem[1]), color: "rgb(153, 153, 153)" });
163
- business && result.push({ label: "额", value: formatPrice(klineItem[4]), color: "rgb(153, 153, 153)" });
164
- if (riseAndFall) {
165
- let ratio = (((klineItem[1] - klineItem[5]) / klineItem[1]) * 100).toFixed(2);
166
- let ratioColor = +ratio === 0.0 ? "white" : +ratio > 0 ? "red" : "#00ff00";
167
- result.push({ label: "涨跌", value: `${ratio}%`, color: ratioColor });
168
- }
169
- return result;
170
- }
171
- return [];
172
- });
173
- // Tips: 指标
174
- const indicatorTips = computed(() => {
175
- if (option.value && option.value.dataset[0]?.source?.indicatorData) {
176
- return option.value.dataset[0].source.indicatorData.reduce((result: any, next: any) => {
177
- next.data[activeIndex.value] &&
178
- result.push({
179
- label: next.key,
180
- value: formatValue(next.data[activeIndex.value]),
181
- color: next.color,
182
- });
183
- return result;
184
- }, []);
185
- }
186
- return [];
187
- });
188
- // Tips: 价格趋势[价差定制]
189
- const priceTrendTips = computed(() => {
190
- // 颜色配置
191
- const colorList = [
192
- "#FFFFFF",
193
- "#FFDD00",
194
- "#FF00FF",
195
- "#00FF00",
196
- "#FF6000",
197
- "#1677FF",
198
- "#7C3CC9",
199
- "#FF0000",
200
- "#FB9A0E",
201
- "#00B7FF",
202
- ];
203
- // 价格趋势
204
- if (props.priceTrendData.length > 0) {
205
- const result = [];
206
- props.priceTrendData.forEach((item: any, index: number) => {
207
- const value = item.data[activeIndex.value] ? formatValue(item.data[activeIndex.value][1]) : null;
208
- if (value !== null) {
209
- result.push({
210
- label: item.name,
211
- value: formatValue(item.data[activeIndex.value]?.[1]),
212
- color: colorList[index],
213
- });
214
- }
215
- });
216
- return result;
217
- }
218
- // 价格趋势百分比
219
- if (props.priceTrendPercentData.length > 0) {
220
- const result = [];
221
- const chartOption = echartsInstance.getOption()
222
- chartOption.series.filter(line => line.name.includes('二腿价格走势百分比图')).forEach((item: any, index: number) => {
223
- const value = item.data[activeIndex.value] ? formatValue(item.data[activeIndex.value][1]) : null;
224
- if (value !== null) {
225
- result.push({
226
- label: item.name.split('-')[1],
227
- value: `${formatValue(item.data[activeIndex.value]?.[1])}%`,
228
- color: colorList[index],
229
- });
230
- }
231
- });
232
- return result;
233
- }
234
- return [];
235
- });
236
-
237
- // 监视: props[klineData, indicator, markData, netPositionData, relevanceData] -> 重绘全部
238
- watch(
239
- () => [props.klineData, props.indicator, props.markData, props.netPositionData, props.relevanceData],
240
- () => {
241
- draw();
242
- },
243
- {
244
- deep: true,
245
- }
246
- );
247
- // 监视: props.lineData - 额外画线数据 -> 重新绘制额外线
248
- watch(
249
- () => props.lineData,
250
- async () => {
251
- printConsole("st-kline组件消息:props.lineData监控,额外画线数据发生改变,重绘->line", {
252
- color: "red",
253
- });
254
- draw("line");
255
- },
256
- {
257
- deep: true,
258
- }
259
- );
260
- // 监视: props.brushRange - 区域刷选数据 -> 重新刷选
261
- watch(
262
- () => props.brushRange,
263
- async () => {
264
- printConsole("st-kline组件消息:props.brushRange监控,区域刷选数据发生改变,重绘->brush", {
265
- color: "red",
266
- });
267
- draw("brush");
268
- },
269
- {
270
- deep: true,
271
- }
272
- );
273
- // 监视: props.priceTrendData - 二腿价格趋势数据 -> 重绘趋势
274
- watch(
275
- () => props.priceTrendData,
276
- async () => {
277
- draw("priceTrend");
278
- },
279
- {
280
- deep: true,
281
- }
282
- );
283
- // 监视: props.priceTrendPercentData - 二腿价格趋势百分比数据 -> 重绘趋势百分比
284
- watch(
285
- () => props.priceTrendPercentData,
286
- async () => {
287
- draw("priceTrendPercent");
288
- },
289
- {
290
- deep: true,
291
- }
292
- );
293
-
294
- /**
295
- * @description: 图表绘制函数
296
- * @param {?String} type 绘制类型[Kline-K线,line-额外线条,brush-区域刷选,不传-全部]
297
- */
298
- const draw = async (type?: string) => {
299
- const callBackMap = new Map([
300
- // kline-K线绘制
301
- [
302
- "kline",
303
- async () => {
304
- const newOption = await getOption(
305
- props.klineData as KlineDataType,
306
- props.markData,
307
- props.indicator,
308
- config.value,
309
- props.netPositionData,
310
- props.relevanceData
311
- );
312
- const { graphic } = echartsInstance.getOption() ?? { graphic: [] };
313
- option.value = { ...newOption, graphic };
314
- echartsInstance.setOption(option.value, true);
315
- printConsole("st-kline组件消息:K线绘制完毕-draw", { color: "green" });
316
- },
317
- ],
318
- // line-额外线条绘制
319
- [
320
- "line",
321
- () => {
322
- const echartsOptions = echartsInstance.getOption();
323
- const graphic = getLineOption(props.lineData as LineDataType, config.value, echartsInstance);
324
- option.value = { ...echartsOptions, graphic };
325
- echartsInstance.setOption(option.value, {
326
- replaceMerge: ["graphic"],
327
- });
328
- printConsole("st-kline组件消息:额外画线绘制完毕-draw", { color: "green" });
329
- },
330
- ],
331
- // brush-区域刷选
332
- [
333
- "brush",
334
- () => {
335
- const { brushRange } = props;
336
- if (brushRange instanceof Array && brushRange.length > 0) {
337
- echartsInstance.dispatchAction({
338
- type: "brush",
339
- areas: [
340
- {
341
- brushType: "lineX",
342
- coordRange: [brushRange[0] + "", brushRange[1] + ""],
343
- xAxisIndex: 0,
344
- },
345
- ],
346
- });
347
- printConsole("st-kline组件消息:区域刷选绘制完毕-draw", { color: "green" });
348
- }
349
- },
350
- ],
351
- // 全部绘制
352
- [
353
- undefined,
354
- async () => {
355
- await draw("kline");
356
- await draw("line");
357
- await draw("priceTrend");
358
- await draw("priceTrendPercent");
359
- await draw("brush");
360
- },
361
- ],
362
- // history-K线历史数据绘制
363
- [
364
- "history",
365
- async () => {
366
- const chartOption = echartsInstance.getOption();
367
- const newOption = await getOption(
368
- props.klineData as KlineDataType,
369
- props.markData,
370
- props.indicator,
371
- config.value,
372
- props.netPositionData,
373
- props.relevanceData
374
- );
375
- const addDataLength =
376
- newOption.dataset.source.klineData.length - chartOption.dataset[0].source.klineData.length;
377
- echartsInstance.setOption(
378
- {
379
- ...newOption,
380
- dataZoom: [
381
- {
382
- type: "inside",
383
- xAxisIndex: [0, 0],
384
- zoomLock: config.value.zoomLock,
385
- maxValueSpan: config.value.maxValueSpan,
386
- startValue: chartOption.dataZoom[0].startValue + addDataLength,
387
- endValue: chartOption.dataZoom[0].endValue + addDataLength,
388
- },
389
- ],
390
- },
391
- true
392
- );
393
- await draw("priceTrend");
394
- },
395
- ],
396
- // future-K线后续数据绘制
397
- [
398
- "future",
399
- async () => {
400
- const chartOption = echartsInstance.getOption();
401
- const newOption = await getOption(
402
- props.klineData as KlineDataType,
403
- props.markData,
404
- props.indicator,
405
- config.value,
406
- props.netPositionData,
407
- props.relevanceData
408
- );
409
- newOption.dataZoom[0].start =
410
- ((props.klineData.length - chartOption.dataZoom[0].endValue + chartOption.dataZoom[0].startValue) /
411
- props.klineData.length) *
412
- 100;
413
- echartsInstance.setOption(newOption, true);
414
- await draw("priceTrend");
415
- },
416
- ],
417
- // priceTrend-二腿价格趋势绘制
418
- [
419
- "priceTrend",
420
- () => {
421
- if (props.priceTrendData.length === 0) return;
422
- const echartsOptions = echartsInstance.getOption();
423
- // 颜色配置
424
- const colorList = [
425
- "#FFFFFF",
426
- "#FFDD00",
427
- "#FF00FF",
428
- "#00FF00",
429
- "#FF6000",
430
- "#1677FF",
431
- "#7C3CC9",
432
- "#FF0000",
433
- "#FB9A0E",
434
- "#00B7FF",
435
- ];
436
- // 格式化series配置
437
- const priceTrendLineSeries = props.priceTrendData.reduce((result, next, index) => {
438
- const { name, data } = next;
439
- const line = {
440
- name: `二腿价格走势图-${name}`,
441
- type: "line",
442
- data,
443
- symbol: "none",
444
- yAxisIndex: 1,
445
- connectNulls: true,
446
- itemStyle: {
447
- color: colorList[index],
448
- },
449
- lineStyle: {
450
- type: "dashed", // 虚线
451
- width: 1,
452
- },
453
- };
454
- result.push(line);
455
- return result;
456
- }, []);
457
- option.value = { ...echartsOptions, series: [...echartsOptions.series, ...priceTrendLineSeries] };
458
- echartsInstance.setOption(option.value, {
459
- replaceMerge: ["series"],
460
- });
461
- },
462
- ],
463
- // priceTrendPercent-二腿价格趋势百分比绘制-初始绘制
464
- [
465
- "priceTrendPercent",
466
- async () => {
467
- if (props.priceTrendPercentData.length === 0) return;
468
- const chartOption = echartsInstance.getOption();
469
- // 颜色配置
470
- const colorList = [
471
- "#FFFFFF",
472
- "#FFDD00",
473
- "#FF00FF",
474
- "#00FF00",
475
- "#FF6000",
476
- "#1677FF",
477
- "#7C3CC9",
478
- "#FF0000",
479
- "#FB9A0E",
480
- "#00B7FF",
481
- ];
482
- // 获取当屏首根K线索引
483
- const startIndex = chartOption.dataZoom[0].startValue;
484
- // 处理趋势数据(百分比)
485
- const handlePriceTrendSeries = props.priceTrendPercentData.reduce((result, next, index) => {
486
- const { name, data } = next;
487
- const handleData = data.length > config.value.totalBarCount ? data.slice(data.length - config.value.totalBarCount) : data
488
- const priceTrendBase = handleData[startIndex][1];
489
- const lineData = handleData.map((item) => {
490
- return [item[0], ((item[1] - priceTrendBase) / priceTrendBase) * 100];
491
- });
492
- const line = {
493
- name: `二腿价格走势百分比图-${name}`,
494
- type: "line",
495
- data: lineData,
496
- symbol: "none",
497
- yAxisIndex: 1,
498
- connectNulls: true,
499
- itemStyle: {
500
- color: colorList[index],
501
- },
502
- lineStyle: {
503
- type: "dashed", // 虚线
504
- width: 1,
505
- },
506
- };
507
- result.push(line);
508
- return result;
509
- }, []);
510
- // 填充价格趋势线(避免重复)
511
- chartOption.series = [...chartOption.series.filter(line => {
512
- return !line.name.includes('二腿价格走势百分比图')
513
- }), ...handlePriceTrendSeries];
514
- echartsInstance.setOption(chartOption, true);
515
- },
516
- ],
517
- ]);
518
- const callBack = callBackMap.get(type);
519
- if (callBack instanceof Function) {
520
- await callBack();
521
- }
522
- };
523
-
524
- //----------------------------右键菜单功能相关----------------------------------
525
- const cursorPenVisible = ref(false); // 画笔模式开关
526
-
527
- const menuData = ref<MenuDataType>([]);
528
-
529
- /**
530
- * @description: 点击菜单项
531
- * @param {Object} item 菜单项的数据
532
- */
533
- const menuClick = (item: any) => {
534
- const { callBack } = item;
535
- callBack instanceof Function && callBack(echartsInstance, cursorPenVisible);
536
- };
537
-
538
- /**
539
- * @description: 菜单关闭的回调
540
- * @todo: 进行菜单内容的初始化
541
- */
542
- const closeContextMenuCallBack = () => {
543
- menuData.value = props.defaultMenuData as MenuDataType;
544
- };
545
-
546
- //----------------------------Echarts基座-------------------------------
547
- const echartsRef = ref<HTMLElement>();
548
- let echartsInstance: EChartsType; // echarts实例
549
- let chartDomObserver: any; // 监视图表DOM变化
550
-
551
- /**
552
- * @description: echarts数据高亮回调
553
- * @param {any} data echarts数据
554
- * @param {EChartsType} chart echarts实例
555
- */
556
- const highlight = (data: any, chart: EChartsType) => {
557
- if (data) {
558
- // 图表内部移动
559
- activeIndex.value = typeof data?.batch[0]?.dataIndex === "number" ? data?.batch[0]?.dataIndex : -1;
560
- } else {
561
- // 移出图表
562
- const chartOptions: EChartsOption = chart.getOption() as EChartsOption;
563
- if (chartOptions.dataZoom instanceof Array) {
564
- activeIndex.value = chartOptions.dataZoom[0].endValue as number;
565
- }
566
- }
567
- };
568
-
569
- /**
570
- * @description: echarts数据缩放的相关参数
571
- * @param {any} datazoomTimer 缩放回调函数的延时器
572
- * @param {Number} datazoomTime 缩放回调函数的延时器的时间
573
- * @param {Function} datazoom 数据缩放的回调函数
574
- *
575
- * 判断具体是拖拽,还是缩放的逻辑
576
- * 根据start~end的差值前后是否变动
577
- * 因为拖拽时,他们的差值是恒定的,缩放时是会变动
578
- */
579
- let datazoomTimer: any = null;
580
- const datazoomTime: number = 300;
581
- let historyIsLoading = false;
582
- let historyIsAllLoad = ref(false);
583
- let futureIsLoading = false;
584
- let futureIsAllLoad = ref(false);
585
- const datazoom = async (params: any) => {
586
- // 执行[方向键]时,返回的是startValue和endValue
587
- // 执行[鼠标]时,返回的是batch
588
- /**
589
- * @description: 历史数据动态加载渲染逻辑
590
- * 前置条件:
591
- * 1.允许开启历史动态加载
592
- * 2.如果剩余K线根数不足100根
593
- * 3.没有正在加载历史数据
594
- * 4.历史数据并未已全部获取
595
- */
596
- // 获取左侧剩余K线根数
597
- const historyLength = params.batch ? params.batch[0].start * config.value.totalBarCount : params.startValue;
598
- if (
599
- config.value.dynamicLoadConfig.historyVisible &&
600
- historyLength <= 100 &&
601
- !historyIsLoading &&
602
- !historyIsAllLoad.value
603
- ) {
604
- historyIsLoading = true;
605
- await config.value.dynamicLoadConfig.historyLoadCallBack(historyIsAllLoad);
606
- await draw("history");
607
- historyIsLoading = false;
608
- }
609
- /**
610
- * @description: 后续数据动态加载渲染逻辑
611
- * 前置条件:
612
- * 1.允许开启后续动态加载
613
- * 2.右侧已为图表尽头
614
- * 3.没有正在加载后续数据
615
- * 4.后续数据并未已全部获取
616
- * 5.仅仅在[鼠标拖拽,方向键左右]时
617
- */
618
- // 获取右侧K线是否最后一根
619
- const nowIsEnd = params.batch
620
- ? params.batch[0].end === 100
621
- : params.endValue >= props.klineData.length - config.value.preBarCount - 1;
622
- const actionIsWheel = params.actionIsWheel;
623
- if (
624
- config.value.dynamicLoadConfig.futureVisible &&
625
- nowIsEnd &&
626
- !futureIsLoading &&
627
- !futureIsAllLoad.value &&
628
- !actionIsWheel
629
- ) {
630
- futureIsLoading = true;
631
- await config.value.dynamicLoadConfig.futureLoadCallBack(futureIsAllLoad);
632
- await draw("future");
633
- futureIsLoading = false;
634
- }
635
- clearTimeout(datazoomTimer);
636
- datazoomTimer = setTimeout(() => {
637
- draw("line");
638
- draw("priceTrendPercent");
639
- clearTimeout(datazoomTimer);
640
- datazoomTimer = null;
641
- }, datazoomTime);
642
- };
643
- /**
644
- * @description: echarts鼠标右击事件回调
645
- */
646
- let echartsContextMenuTimer: any = null;
647
- const echartsContextMenu = (params: ECElementEvent) => {
648
- echartsContextMenuTimer = setTimeout(() => {
649
- // 判定是否点击到的元素为额外画线
650
- if (params.componentType === "graphic") {
651
- const { oncontextmenu } = params.info?.event ?? {};
652
- oncontextmenu instanceof Function && oncontextmenu(params, params.info, menuData);
653
- }
654
- clearTimeout(echartsContextMenuTimer);
655
- echartsContextMenuTimer = null;
656
- });
657
- };
658
-
659
- // 绑定事件
660
- const addEventListener = () => {
661
- echartsInstance.on("highlight", (data: any) => {
662
- highlight(data, echartsInstance);
663
- });
664
- echartsInstance.on("globalout", () => {
665
- highlight(null, echartsInstance);
666
- });
667
- echartsInstance.on("contextmenu", (params: ECElementEvent) => {
668
- echartsContextMenu(params);
669
- });
670
- echartsInstance.on("datazoom", (params: any) => {
671
- datazoom(params);
672
- });
673
- };
674
-
675
- // 解绑事件
676
- const removeEventListener = () => {
677
- echartsInstance.off("highlight");
678
- echartsInstance.off("globalout");
679
- echartsInstance.off("contextmenu");
680
- echartsInstance.off("datazoom");
681
- };
682
-
683
- // 键盘事件
684
- const keyDownEvent = (e: KeyboardEvent) => {
685
- if (!echartsInstance) return;
686
- // 只有选中或者按ctrl才激活按键
687
- if (!(e.ctrlKey || props.isSelect)) return;
688
- const option = echartsInstance.getOption() as EChartsOption;
689
- let { startValue, endValue, start, end } = (option.dataZoom as DataZoomComponentOption[])[0] as {
690
- startValue: number;
691
- endValue: number;
692
- };
693
- const handleLeft = () => {
694
- // 左按键
695
- if (startValue === 0) {
696
- return;
697
- }
698
- startValue = startValue - 1;
699
- endValue = endValue - 1;
700
- echartsInstance.dispatchAction({
701
- type: "dataZoom",
702
- startValue,
703
- endValue,
704
- maxValueSpan: config.value.maxValueSpan,
705
- });
706
- };
707
- const handleRight = () => {
708
- // 右按键
709
- // 如果开启了动态后续数据加载
710
- if (config.value.dynamicLoadConfig.futureVisible && !futureIsLoading && !futureIsAllLoad.value) {
711
- startValue = startValue + 1;
712
- endValue = endValue + 1;
713
- echartsInstance.dispatchAction({
714
- type: "dataZoom",
715
- startValue,
716
- endValue,
717
- maxValueSpan: config.value.maxValueSpan,
718
- });
719
- } else {
720
- if (endValue === option.xAxis[0].data.length - 1) {
721
- return;
722
- }
723
- startValue = startValue + 1;
724
- endValue = endValue + 1;
725
- echartsInstance.dispatchAction({
726
- type: "dataZoom",
727
- startValue,
728
- endValue,
729
- maxValueSpan: config.value.maxValueSpan,
730
- });
731
- }
732
- };
733
- const handleUp = () => {
734
- // 上按键-放大 最少保持5条数据
735
- if (endValue - startValue < 5) {
736
- return;
737
- }
738
- // 以鼠标指定的K线为中心点进行放大
739
- const startDiff = Math.floor((activeIndex.value - startValue) / 2) + 1;
740
- const endDiff = Math.floor((endValue - activeIndex.value) / 2) + 1;
741
- startValue = startValue + startDiff;
742
- endValue = endValue - endDiff;
743
- echartsInstance.dispatchAction({
744
- type: "dataZoom",
745
- startValue,
746
- endValue,
747
- actionIsWheel: true, // 标记为缩放
748
- maxValueSpan: config.value.maxValueSpan,
749
- });
750
- };
751
- const handleDown = () => {
752
- // 下按键-缩小
753
- // const diff = Math.min(50, activeIndex.value - startValue);
754
- // startValue = startValue - diff - 1;
755
- start = start - (end - start) / 4;
756
- echartsInstance.dispatchAction({
757
- type: "dataZoom",
758
- start,
759
- end,
760
- actionIsWheel: true, // 标记为缩放
761
- maxValueSpan: config.value.maxValueSpan,
762
- });
763
- };
764
- const callBackMap = new Map([
765
- ["ArrowLeft", handleLeft],
766
- ["ArrowRight", handleRight],
767
- ["ArrowUp", handleUp],
768
- ["ArrowDown", handleDown],
769
- ]);
770
- const callBack = callBackMap.get(e.code);
771
- callBack instanceof Function && callBack();
772
- };
773
-
774
- /**
775
- * @description: K线组件初始化
776
- */
777
- const init = async () => {
778
- let Initializing: boolean | null = true; // 正在初始化
779
- // 1.初始化图表
780
- echartsInstance = echarts.init(echartsRef.value) as EChartsType;
781
- // 2.绘制
782
- await draw();
783
- // 3.初始化右键菜单
784
- menuData.value = props.defaultMenuData as MenuDataType;
785
- // 4.初始化数据激活索引
786
- activeIndex.value = ((echartsInstance.getOption().dataZoom as DataZoomComponentOption[])[0].endValue as number) ?? -1;
787
- // 5.进行图表事件绑定
788
- addEventListener();
789
- // 6.进行DOM监控,图表重加载
790
- chartDomObserver = new ResizeObserver(() => {
791
- if (Initializing) {
792
- Initializing = null;
793
- return;
794
- }
795
- echartsInstance.resize();
796
- draw("line");
797
- });
798
- chartDomObserver.observe(echartsRef.value);
799
- // 7.绑定键盘事件
800
- window.addEventListener("keydown", keyDownEvent);
801
- };
802
-
803
- onMounted(() => {
804
- init();
805
- });
806
-
807
- onUnmounted(() => {
808
- // 1.解绑
809
- removeEventListener();
810
- window.removeEventListener("keydown", keyDownEvent);
811
- // 2.销毁实例
812
- echartsInstance.dispose();
813
- // 3.取消监听图表DOM
814
- chartDomObserver.disconnect();
815
- chartDomObserver = null;
816
- });
817
- </script>
818
-
819
- <template>
820
- <!-- 神兔-K线组件 -->
821
- <div class="st-kline">
822
- <!-- Tips -->
823
- <div class="st-kline-header">
824
- <!-- 开, 高, 低, 收 -->
825
- <Tips :data="kLineTips" />
826
- <!-- 指标 -->
827
- <Tips :data="indicatorTips" />
828
- <!-- 价格趋势[价差定制] -->
829
- <Tips :data="priceTrendTips" />
830
- </div>
831
- <!-- 图表 + 菜单 -->
832
- <Contextmenu class="st-kline-body" @closeContextMenuCallBack="closeContextMenuCallBack">
833
- <!-- 图表 -->
834
- <div ref="echartsRef" :class="cursorPenVisible ? 'st-kline-chart cursorPen' : 'st-kline-chart'" />
835
- <!-- 菜单 -->
836
- <template #popover>
837
- <el-menu class="menu">
838
- <el-menu-item
839
- v-for="item in menuData"
840
- :key="item.label"
841
- :index="item.label"
842
- class="menuItem"
843
- @click="menuClick(item)"
844
- >
845
- {{ item.label }}
846
- </el-menu-item>
847
- </el-menu>
848
- </template>
849
- </Contextmenu>
850
- </div>
851
- </template>
852
-
853
- <style lang="scss">
854
- // 需要写在外面,不然会被Vue唯一标识符顶掉导致样式不生效
855
- .cursorPen canvas {
856
- cursor: url(./images/pen.png) -30 30, auto !important;
857
- }
858
- </style>
859
- <style lang="scss" scoped>
860
- .st-kline {
861
- width: 100%;
862
- height: 100%;
863
- background: #000;
864
- overflow-x: hidden;
865
- position: relative; // 配合提供给菜单定位
866
- // K线头部区域: Tips
867
- &-header {
868
- height: 34px;
869
- position: absolute;
870
- left: 66px;
871
- }
872
- &-body {
873
- width: 100%;
874
- height: 100%;
875
- }
876
- &-chart {
877
- width: 100%;
878
- height: 100%;
879
- }
880
- .menu {
881
- border-radius: 4px;
882
- overflow: hidden;
883
- background-color: white;
884
- border-right: 0;
885
- .menuItem {
886
- font-size: 16px;
887
- height: 32px;
888
- }
889
- }
890
- }
891
- </style>