st-comp 0.0.62 → 0.0.64
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/lib/bundle.js +16232 -15782
- package/lib/bundle.umd.cjs +49 -49
- package/lib/style.css +1 -1
- package/package.json +1 -1
- package/packages/Kline/componentsNew/KlineSlide/index.vue +155 -0
- package/packages/Kline/componentsNew/KlineSub/index.vue +282 -0
- package/packages/Kline/componentsNew/KlineTips/index.vue +66 -0
- package/packages/Kline/componentsNew/KlineUtils/index.vue +83 -0
- package/packages/Kline/componentsNew/Tips/index.vue +33 -0
- package/packages/Kline/index.ts +16 -8
- package/src/pages/KlineNew/components/KlineBasic/utils.js +15 -2
- package/src/pages/KlineNew/components/KlineNew/index.vue +317 -0
- package/src/pages/KlineNew/components/KlineNew/utils.js +31 -0
- package/src/pages/KlineNew/components/KlineSlideNew/index.vue +430 -0
- package/src/pages/KlineNew/components/KlineSlideNew/utils.js +78 -0
- package/src/pages/KlineNew/index.vue +24 -12
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="kline"
|
|
4
|
+
@mousemove="isSelect = true"
|
|
5
|
+
@mouseout="isSelect = false"
|
|
6
|
+
>
|
|
7
|
+
<div class="kline-mainTips">
|
|
8
|
+
<st-kline-tips-new :data="klineData" :activeIndex="activeIndex"/>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="kline-mainChart" ref="mainChartRef"></div>
|
|
11
|
+
<div class="kline-sub">
|
|
12
|
+
<st-kline-sub-new
|
|
13
|
+
ref="klineSubRef"
|
|
14
|
+
v-model="subIndicator"
|
|
15
|
+
:data="klineData"
|
|
16
|
+
:activeIndex="activeIndex"
|
|
17
|
+
:subIndicatorList="subIndicatorList"
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
<st-kline-utils-new ref="klineUtilsRef" />
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref, onMounted, onUnmounted, watch, computed } from "vue"
|
|
26
|
+
import * as echarts from 'echarts'
|
|
27
|
+
import { getKlineDataApi, formatConfig } from './utils'
|
|
28
|
+
import dayjs from "dayjs"
|
|
29
|
+
import { stMath } from 'st-func'
|
|
30
|
+
const { round } = stMath
|
|
31
|
+
|
|
32
|
+
const props = defineProps({
|
|
33
|
+
code: { type: String, required: true }, // 品种代码
|
|
34
|
+
freqId: { type: String, required: true }, // 周期
|
|
35
|
+
freqDict: { type: Object, required: true }, // 周期字典
|
|
36
|
+
mainIndicator: { type: String, required: true }, // 主图指标
|
|
37
|
+
mainIndicatorList: { type: Array, required: true }, // 主图指标列表
|
|
38
|
+
subIndicatorList: { type: Array, required: true }, // 副图指标列表
|
|
39
|
+
config: { type: Object, default: () => ({}) }, // 配置
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
let mainChart
|
|
43
|
+
let mainDataZoomTimer = null // 主图数据缩放定时器
|
|
44
|
+
let isLoadHistory = false // 是否正在加载历史数据
|
|
45
|
+
let isloadAllHistory = false // 是否加载完全部历史数据
|
|
46
|
+
let resizeRo // dom元素监听事件
|
|
47
|
+
let highlightTimer = null // 高亮处理事件的定时器
|
|
48
|
+
const activeIndex = ref(0) // 显示的index
|
|
49
|
+
|
|
50
|
+
const mainChartRef = ref() // 主图
|
|
51
|
+
const klineSubRef = ref() // 副图
|
|
52
|
+
const klineUtilsRef = ref() // k线辅助函数实例
|
|
53
|
+
const isSelect = ref(false) // 是否选中,选中可通过键盘按键操作
|
|
54
|
+
const klineData = ref({}) // 绘图数据
|
|
55
|
+
const subIndicator = ref('VOL') // 副图指标
|
|
56
|
+
|
|
57
|
+
const config = computed(() => formatConfig(props.config))
|
|
58
|
+
|
|
59
|
+
watch(
|
|
60
|
+
() => [props.code, props.freqId, props.mainIndicator, subIndicator],
|
|
61
|
+
async () => {
|
|
62
|
+
initChart()
|
|
63
|
+
},
|
|
64
|
+
{ deep: true }
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
onMounted(async () => {
|
|
68
|
+
// 初始化指标计算方法
|
|
69
|
+
mainChart = echarts.init(mainChartRef.value)
|
|
70
|
+
klineSubRef.value.connect(mainChart)
|
|
71
|
+
addEventListener()
|
|
72
|
+
initChart()
|
|
73
|
+
// 绑定resize事件
|
|
74
|
+
let isFirst = true
|
|
75
|
+
resizeRo = new ResizeObserver(() => {
|
|
76
|
+
if (isFirst) {
|
|
77
|
+
isFirst = null
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
mainChart.resize()
|
|
81
|
+
})
|
|
82
|
+
resizeRo.observe(mainChartRef.value)
|
|
83
|
+
window.addEventListener('keydown', keyDownEvent)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
onUnmounted(() => {
|
|
87
|
+
window.removeEventListener('keydown', keyDownEvent)
|
|
88
|
+
mainChart.off('datazoom')
|
|
89
|
+
mainChart.off('highlight')
|
|
90
|
+
mainChart.off('globalout')
|
|
91
|
+
mainChart.dispose()
|
|
92
|
+
resizeRo.disconnect()
|
|
93
|
+
resizeRo = null
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// 项目初始化
|
|
97
|
+
const initChart = async () => {
|
|
98
|
+
const { addCount } = config.value
|
|
99
|
+
const res = await getKlineDataApi({
|
|
100
|
+
variety: props.code,
|
|
101
|
+
contractType: 0, // 合约类型 0-主连 1-加权
|
|
102
|
+
right: 1,
|
|
103
|
+
cycle: 5,
|
|
104
|
+
mainIndicator: props.mainIndicator,
|
|
105
|
+
subIndicator: subIndicator.value,
|
|
106
|
+
endTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
|
107
|
+
limit: addCount,
|
|
108
|
+
})
|
|
109
|
+
klineData.value = res
|
|
110
|
+
draw('main', { startValue: res.time.length - 1 - config.value.defaultShowCount, endValue: res.time.length - 1 })
|
|
111
|
+
draw('sub', { startValue: res.time.length - 1 - config.value.defaultShowCount, endValue: res.time.length - 1 })
|
|
112
|
+
activeIndex.value = mainChart.getOption().dataZoom[0].endValue
|
|
113
|
+
}
|
|
114
|
+
// 绑定事件
|
|
115
|
+
const addEventListener = () => {
|
|
116
|
+
mainChart.on('datazoom', (params) => {
|
|
117
|
+
clearTimeout(mainDataZoomTimer)
|
|
118
|
+
mainDataZoomTimer = setTimeout(() => {
|
|
119
|
+
const { loadCheckCount, addCount } = config.value
|
|
120
|
+
const { startValue } = mainChart.getOption().dataZoom[0]
|
|
121
|
+
// 加载数据
|
|
122
|
+
if (startValue < loadCheckCount && isLoadHistory === false && isloadAllHistory === false) {
|
|
123
|
+
// 左侧数据小于1000条,加载左侧数据
|
|
124
|
+
isLoadHistory = true
|
|
125
|
+
getMoreData()
|
|
126
|
+
}
|
|
127
|
+
clearTimeout(mainDataZoomTimer)
|
|
128
|
+
}, 100)
|
|
129
|
+
})
|
|
130
|
+
// 高亮事件
|
|
131
|
+
mainChart.on('highlight', (data) => {
|
|
132
|
+
let index = data.dataIndex || -1
|
|
133
|
+
if (data.batch ) {
|
|
134
|
+
index = typeof data?.batch[0]?.dataIndex === 'number' ? data?.batch[0]?.dataIndex : -1
|
|
135
|
+
}
|
|
136
|
+
clearTimeout(highlightTimer)
|
|
137
|
+
highlightTimer = setTimeout(() => {
|
|
138
|
+
activeIndex.value = index
|
|
139
|
+
clearTimeout(highlightTimer)
|
|
140
|
+
}, 20)
|
|
141
|
+
})
|
|
142
|
+
// 移出图表事件
|
|
143
|
+
mainChart.on('globalout', () => {
|
|
144
|
+
const index = mainChart.getOption().dataZoom[0].endValue
|
|
145
|
+
activeIndex.value = index
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 键盘事件
|
|
150
|
+
const keyDownEvent = e => {
|
|
151
|
+
// 只有选中或者按ctrl才激活按键
|
|
152
|
+
if (!(e.ctrlKey || isSelect.value)) return
|
|
153
|
+
const option = mainChart.getOption()
|
|
154
|
+
let { startValue, endValue } = option.dataZoom[0]
|
|
155
|
+
mainChart.dispatchAction({
|
|
156
|
+
type: 'dataZoom',
|
|
157
|
+
...klineUtilsRef.value.handleKeyDown(e, { startValue, endValue, maxIndex: option.xAxis[0].data.length - 1})
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 获取更多数据
|
|
162
|
+
const getMoreData = async(params) => {
|
|
163
|
+
const { addCount, maxLoadCount } = config.value
|
|
164
|
+
const res = await getKlineDataApi({
|
|
165
|
+
variety: props.code,
|
|
166
|
+
contractType: 0, // 合约类型 0-主连 1-加权
|
|
167
|
+
right: 1,
|
|
168
|
+
cycle: 5,
|
|
169
|
+
mainIndicator: props.mainIndicator,
|
|
170
|
+
subIndicator: subIndicator.value,
|
|
171
|
+
endTime: klineData.value.time[0],
|
|
172
|
+
limit: addCount,
|
|
173
|
+
})
|
|
174
|
+
klineData.value = klineUtilsRef.value.mergeData(res, klineData.value)
|
|
175
|
+
const { startValue, endValue } = mainChart.getOption().dataZoom[0]
|
|
176
|
+
let dataZoomAddCount = addCount
|
|
177
|
+
if(klineData.value.time.length > maxLoadCount){
|
|
178
|
+
// 超出设置的最长加载数据条数
|
|
179
|
+
isloadAllHistory = true
|
|
180
|
+
} else if (res.time.length < addCount) {
|
|
181
|
+
// 表示历史数据已加载完
|
|
182
|
+
isloadAllHistory = true
|
|
183
|
+
dataZoomAddCount = res.length - 1
|
|
184
|
+
}
|
|
185
|
+
isLoadHistory = false
|
|
186
|
+
draw('main', { startValue: startValue + dataZoomAddCount, endValue: endValue + dataZoomAddCount })
|
|
187
|
+
draw('sub', { startValue: startValue + dataZoomAddCount, endValue: endValue + dataZoomAddCount })
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 绘制函数
|
|
191
|
+
const draw = (type, params = {}) => {
|
|
192
|
+
const { startValue, endValue, maxValueSpan } = params
|
|
193
|
+
const callBackMap = new Map([
|
|
194
|
+
[ "main", () => {
|
|
195
|
+
const { data, time } = klineData.value
|
|
196
|
+
const indicatorSeries = klineData.value.mainIndicator.map((item) => {
|
|
197
|
+
return {
|
|
198
|
+
name: item.key,
|
|
199
|
+
type: 'line',
|
|
200
|
+
silent: true,
|
|
201
|
+
symbol: 'none',
|
|
202
|
+
data: item.data,
|
|
203
|
+
lineStyle: {
|
|
204
|
+
width: item.width || 1,
|
|
205
|
+
},
|
|
206
|
+
itemStyle: {
|
|
207
|
+
color: item.color,
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
mainChart.setOption({
|
|
212
|
+
animation: false,
|
|
213
|
+
grid: {
|
|
214
|
+
left: `${config.value.gridLeft}px`,
|
|
215
|
+
top: '20px',
|
|
216
|
+
right: `${config.value.gridRight}px`,
|
|
217
|
+
bottom: '6px',
|
|
218
|
+
},
|
|
219
|
+
dataZoom: [
|
|
220
|
+
{
|
|
221
|
+
type: 'inside',
|
|
222
|
+
startValue,
|
|
223
|
+
endValue,
|
|
224
|
+
maxValueSpan: config.value.maxShowCount,
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
tooltip: {
|
|
228
|
+
trigger: 'axis',
|
|
229
|
+
appendToBody: true,
|
|
230
|
+
confine: true,
|
|
231
|
+
axisPointer: {
|
|
232
|
+
type: 'cross',
|
|
233
|
+
label: {
|
|
234
|
+
rich: {},
|
|
235
|
+
formatter: data => {
|
|
236
|
+
const { axisDimension, value } = data
|
|
237
|
+
if(axisDimension === 'x') {
|
|
238
|
+
return ''
|
|
239
|
+
} else {
|
|
240
|
+
return String(round(value))
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
formatter: () => '',
|
|
246
|
+
},
|
|
247
|
+
xAxis: {
|
|
248
|
+
show: false,
|
|
249
|
+
type: 'category',
|
|
250
|
+
data: time,
|
|
251
|
+
splitLine: {
|
|
252
|
+
show: false,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
yAxis: {
|
|
256
|
+
type: 'value',
|
|
257
|
+
axisLine: {
|
|
258
|
+
show: true,
|
|
259
|
+
},
|
|
260
|
+
splitLine: {
|
|
261
|
+
show: true,
|
|
262
|
+
lineStyle: {
|
|
263
|
+
type: "dotted",
|
|
264
|
+
color: "#333",
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
min: (value) => round(value.min),
|
|
268
|
+
max: (value) => round(value.max),
|
|
269
|
+
},
|
|
270
|
+
series: [
|
|
271
|
+
{
|
|
272
|
+
type: 'candlestick',
|
|
273
|
+
data,
|
|
274
|
+
itemStyle: {
|
|
275
|
+
color: "transparent",
|
|
276
|
+
color0: "#00FFFF",
|
|
277
|
+
borderColor: "#FF0000",
|
|
278
|
+
borderColor0: "#00FFFF",
|
|
279
|
+
borderWidth: 1,
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
...indicatorSeries,
|
|
283
|
+
]
|
|
284
|
+
}, true)
|
|
285
|
+
}],
|
|
286
|
+
[ "sub", () => {
|
|
287
|
+
klineSubRef.value.draw({ startValue, endValue, maxValueSpan }, config.value)
|
|
288
|
+
}],
|
|
289
|
+
]);
|
|
290
|
+
const callBack = callBackMap.get(type);
|
|
291
|
+
if (callBack instanceof Function) {
|
|
292
|
+
callBack();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
</script>
|
|
296
|
+
|
|
297
|
+
<style lang="scss" scoped>
|
|
298
|
+
.kline {
|
|
299
|
+
width: 100%;
|
|
300
|
+
height: 100%;
|
|
301
|
+
background: #000;
|
|
302
|
+
&-mainTips {
|
|
303
|
+
height: 26px;
|
|
304
|
+
}
|
|
305
|
+
&-mainChart {
|
|
306
|
+
width: 100%;
|
|
307
|
+
height: calc(65% - 26px);
|
|
308
|
+
}
|
|
309
|
+
&-subTips {
|
|
310
|
+
height: 16px;
|
|
311
|
+
}
|
|
312
|
+
&-sub {
|
|
313
|
+
width: 100%;
|
|
314
|
+
height: calc(35%);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
const defaultConfig = {
|
|
4
|
+
defaultShowCount: 500, // 默认展示天数
|
|
5
|
+
addCount: 2000, // 首屏加载条数,滚动加载条数
|
|
6
|
+
maxLoadCount: 50000, // 最多加载多少条数据
|
|
7
|
+
maxShowCount: 5000, // 一屏幕最多展示多少条数据
|
|
8
|
+
loadCheckCount: 500, // 加载数据检查条数
|
|
9
|
+
gridLeft: 60, // echarts绘图左侧grid距离
|
|
10
|
+
gridRight: 20, // echarts绘图右侧grid距离
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// 获取配置
|
|
14
|
+
export const formatConfig = (config) => {
|
|
15
|
+
return {
|
|
16
|
+
...defaultConfig,
|
|
17
|
+
...config,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const getKlineDataApi = async(params) => {
|
|
22
|
+
const res = await axios({
|
|
23
|
+
method: 'post',
|
|
24
|
+
headers: {
|
|
25
|
+
token: '524164e2c6b6ae23bd25c690a7c6bf96',
|
|
26
|
+
},
|
|
27
|
+
url: 'http://127.0.0.1:7001/middleLayer/kline/getKline',
|
|
28
|
+
data: params,
|
|
29
|
+
})
|
|
30
|
+
return res.data.body
|
|
31
|
+
}
|