@363045841yyt/klinechart 0.8.0 → 0.8.1-alpha.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/components/KLineChart.vue.d.ts.map +1 -1
- package/dist/components/SymbolSelector.vue.d.ts +20 -0
- package/dist/components/SymbolSelector.vue.d.ts.map +1 -0
- package/dist/components/TopToolbar.vue.d.ts +7 -0
- package/dist/components/TopToolbar.vue.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.css +1 -1
- package/dist/index.js +722 -434
- package/package.json +1 -1
- package/src/components/KLineChart.vue +75 -88
- package/src/components/SymbolSelector.vue +478 -0
- package/src/components/TopToolbar.vue +62 -84
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="chartWrapperRef" class="chart-wrapper" :data-theme="chartTheme" :style="themeCssVars">
|
|
3
|
-
<TopToolbar
|
|
4
|
-
:symbol="
|
|
3
|
+
<TopToolbar
|
|
4
|
+
:symbol="currentSymbol"
|
|
5
5
|
:k-line-level="kLineLevel"
|
|
6
|
+
:symbol-loading="symbolLoading"
|
|
7
|
+
:symbol-error="symbolError"
|
|
6
8
|
@add-overlay-symbol="$emit('addOverlaySymbol')"
|
|
7
9
|
@k-line-level-change="onKLineLevelChange"
|
|
8
10
|
@toggle-indicator="onToggleIndicator"
|
|
11
|
+
@symbol-change="onSymbolChange"
|
|
9
12
|
/>
|
|
10
13
|
<div
|
|
11
14
|
class="chart-stage"
|
|
@@ -120,7 +123,6 @@
|
|
|
120
123
|
import { ref, computed, onMounted, onUnmounted, watch, nextTick, shallowRef } from 'vue'
|
|
121
124
|
import {
|
|
122
125
|
SemanticChartController,
|
|
123
|
-
__setDataFetcher,
|
|
124
126
|
type SemanticChartConfig,
|
|
125
127
|
type DataFetcher,
|
|
126
128
|
} from '@363045841yyt/klinechart-core/semantic'
|
|
@@ -149,9 +151,15 @@ import {
|
|
|
149
151
|
} from '@363045841yyt/klinechart-core/indicators'
|
|
150
152
|
import type { DrawingObject, DrawingStyle } from '@363045841yyt/klinechart-core/plugin'
|
|
151
153
|
import type { ChartSettings } from '@363045841yyt/klinechart-core/config'
|
|
152
|
-
import {
|
|
154
|
+
import {
|
|
155
|
+
resolveThemeColors,
|
|
156
|
+
themeToCssVars,
|
|
157
|
+
lightTheme,
|
|
158
|
+
darkTheme,
|
|
159
|
+
type ColorPresetSettings,
|
|
160
|
+
} from '@363045841yyt/klinechart-core'
|
|
153
161
|
import LeftToolbar from './LeftToolbar.vue'
|
|
154
|
-
import TopToolbar from './TopToolbar.vue'
|
|
162
|
+
import TopToolbar, { type SymbolItem } from './TopToolbar.vue'
|
|
155
163
|
|
|
156
164
|
const props = withDefaults(
|
|
157
165
|
defineProps<{
|
|
@@ -195,17 +203,36 @@ const emit = defineEmits<{
|
|
|
195
203
|
(e: 'zoomLevelChange', level: number, kWidth: number): void
|
|
196
204
|
(e: 'toggleFullscreen'): void
|
|
197
205
|
(e: 'themeChange', theme: 'light' | 'dark'): void
|
|
198
|
-
(e: 'addOverlaySymbol'): void
|
|
206
|
+
(e: 'addOverlaySymbol'): void
|
|
199
207
|
(e: 'kLineLevelChange', level: string): void
|
|
200
208
|
}>()
|
|
201
209
|
|
|
202
210
|
const kLineLevel = ref(props.semanticConfig.data.period)
|
|
211
|
+
const currentSymbol = ref('选择商品')
|
|
212
|
+
const symbolLoading = ref(false)
|
|
213
|
+
const symbolError = ref(false)
|
|
203
214
|
|
|
204
215
|
function onKLineLevelChange(level: string) {
|
|
205
216
|
kLineLevel.value = level as typeof kLineLevel.value
|
|
206
217
|
emit('kLineLevelChange', level)
|
|
207
218
|
}
|
|
208
219
|
|
|
220
|
+
function onSymbolChange(item: SymbolItem) {
|
|
221
|
+
symbolError.value = false
|
|
222
|
+
currentSymbol.value = item.code
|
|
223
|
+
controller.value?.setSymbols([
|
|
224
|
+
{
|
|
225
|
+
symbol: item.code,
|
|
226
|
+
exchange: item.exchange,
|
|
227
|
+
period: kLineLevel.value,
|
|
228
|
+
source: item.source,
|
|
229
|
+
startDate: props.semanticConfig.data.startDate,
|
|
230
|
+
endDate: props.semanticConfig.data.endDate,
|
|
231
|
+
adjust: props.semanticConfig.data.adjust,
|
|
232
|
+
},
|
|
233
|
+
])
|
|
234
|
+
}
|
|
235
|
+
|
|
209
236
|
const containerRef = ref<HTMLDivElement | null>(null)
|
|
210
237
|
const chartMainRef = ref<HTMLDivElement | null>(null)
|
|
211
238
|
const chartWrapperRef = ref<HTMLDivElement | null>(null)
|
|
@@ -258,7 +285,9 @@ const tooltipColors = computed(() => {
|
|
|
258
285
|
|
|
259
286
|
const themeCssVars = computed(() => {
|
|
260
287
|
const theme = chartTheme.value === 'dark' ? darkTheme : lightTheme
|
|
261
|
-
const overrides = (chartSettings.value.colorPresetSettings as ColorPresetSettings | undefined)?.[
|
|
288
|
+
const overrides = (chartSettings.value.colorPresetSettings as ColorPresetSettings | undefined)?.[
|
|
289
|
+
chartTheme.value
|
|
290
|
+
]
|
|
262
291
|
if (overrides && Object.keys(overrides).length > 0) {
|
|
263
292
|
return themeToCssVars({ ...theme, colors: { ...theme.colors, ...overrides } })
|
|
264
293
|
}
|
|
@@ -299,55 +328,10 @@ function handleSettingsChange(settings: ChartSettings) {
|
|
|
299
328
|
applyThemeFromSettings(controller.value, settings.theme as string)
|
|
300
329
|
controller.value?.updateSettingsFacade(settings)
|
|
301
330
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
controller.value?.updateData(testData)
|
|
306
|
-
console.timeEnd('updateData-10k')
|
|
307
|
-
dataLength.value = testData.length
|
|
308
|
-
dataVersion.value++
|
|
309
|
-
} else {
|
|
310
|
-
if (semanticController.value && controller.value?.getData()?.length === 10000) {
|
|
311
|
-
semanticController.value.applyConfig(props.semanticConfig)
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// 生成1万条K线测试数据
|
|
317
|
-
function generate10kKLineData() {
|
|
318
|
-
const data: KLineData[] = []
|
|
319
|
-
const startTime = new Date('2020-01-01').getTime()
|
|
320
|
-
const dayMs = 24 * 60 * 60 * 1000
|
|
321
|
-
|
|
322
|
-
let lastClose = 3000 // 起始价格
|
|
323
|
-
|
|
324
|
-
for (let i = 0; i < 10000; i++) {
|
|
325
|
-
const timestamp = startTime + i * dayMs
|
|
326
|
-
|
|
327
|
-
// 生成随机波动
|
|
328
|
-
const volatility = 0.02 // 2%日波动率
|
|
329
|
-
const trend = 0.0001 // 轻微上涨趋势
|
|
330
|
-
const change = (Math.random() - 0.5) * 2 * volatility + trend
|
|
331
|
-
|
|
332
|
-
const open = lastClose
|
|
333
|
-
const close = open * (1 + change)
|
|
334
|
-
const high = Math.max(open, close) * (1 + Math.random() * 0.01)
|
|
335
|
-
const low = Math.min(open, close) * (1 - Math.random() * 0.01)
|
|
336
|
-
const volume = Math.floor(1000000 + Math.random() * 5000000)
|
|
337
|
-
|
|
338
|
-
data.push({
|
|
339
|
-
timestamp,
|
|
340
|
-
open: parseFloat(open.toFixed(2)),
|
|
341
|
-
high: parseFloat(high.toFixed(2)),
|
|
342
|
-
low: parseFloat(low.toFixed(2)),
|
|
343
|
-
close: parseFloat(close.toFixed(2)),
|
|
344
|
-
volume,
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
lastClose = close
|
|
331
|
+
controller.value?.setDataFetcher(props.dataFetcher)
|
|
332
|
+
if (semanticController.value && props.semanticConfig) {
|
|
333
|
+
semanticController.value.applyConfig(props.semanticConfig)
|
|
348
334
|
}
|
|
349
|
-
|
|
350
|
-
return data
|
|
351
335
|
}
|
|
352
336
|
|
|
353
337
|
function measureTooltipSize(el: HTMLDivElement, minWidth: number, minHeight: number) {
|
|
@@ -736,9 +720,24 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
|
|
|
736
720
|
if (!c) return
|
|
737
721
|
|
|
738
722
|
const mainIndicatorIds = [
|
|
739
|
-
'MA',
|
|
740
|
-
'
|
|
741
|
-
'
|
|
723
|
+
'MA',
|
|
724
|
+
'BOLL',
|
|
725
|
+
'EXPMA',
|
|
726
|
+
'ENE',
|
|
727
|
+
'WMA',
|
|
728
|
+
'DEMA',
|
|
729
|
+
'TEMA',
|
|
730
|
+
'HMA',
|
|
731
|
+
'KAMA',
|
|
732
|
+
'SAR',
|
|
733
|
+
'SUPERTREND',
|
|
734
|
+
'KELTNER',
|
|
735
|
+
'DONCHIAN',
|
|
736
|
+
'ICHIMOKU',
|
|
737
|
+
'PIVOT',
|
|
738
|
+
'FIB',
|
|
739
|
+
'STRUCTURE',
|
|
740
|
+
'ZONES',
|
|
742
741
|
]
|
|
743
742
|
if (mainIndicatorIds.includes(indicatorId)) {
|
|
744
743
|
const existingIndicator = mainActiveIndicators.value.find((id) => id === indicatorId)
|
|
@@ -772,8 +771,10 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
|
|
|
772
771
|
|
|
773
772
|
function handleUpdateParams(indicatorId: string, params: Record<string, unknown>) {
|
|
774
773
|
if (
|
|
775
|
-
indicatorId === 'MA' ||
|
|
776
|
-
indicatorId === '
|
|
774
|
+
indicatorId === 'MA' ||
|
|
775
|
+
indicatorId === 'BOLL' ||
|
|
776
|
+
indicatorId === 'EXPMA' ||
|
|
777
|
+
indicatorId === 'ENE'
|
|
777
778
|
) {
|
|
778
779
|
controller.value?.updateIndicatorParams(indicatorId, params)
|
|
779
780
|
return
|
|
@@ -942,11 +943,7 @@ function setupChartCallbacks(ctrl: ChartController): void {
|
|
|
942
943
|
if (viewWidth.value !== vp.plotWidth) {
|
|
943
944
|
viewWidth.value = vp.plotWidth
|
|
944
945
|
}
|
|
945
|
-
if (
|
|
946
|
-
zoomLevel.value !== vp.zoomLevel ||
|
|
947
|
-
kWidth.value !== vp.kWidth ||
|
|
948
|
-
kGap.value !== vp.kGap
|
|
949
|
-
) {
|
|
946
|
+
if (zoomLevel.value !== vp.zoomLevel || kWidth.value !== vp.kWidth || kGap.value !== vp.kGap) {
|
|
950
947
|
zoomLevel.value = vp.zoomLevel
|
|
951
948
|
kWidth.value = vp.kWidth
|
|
952
949
|
kGap.value = vp.kGap
|
|
@@ -970,6 +967,11 @@ function setupChartCallbacks(ctrl: ChartController): void {
|
|
|
970
967
|
const data = ctrl.data.peek()
|
|
971
968
|
dataLength.value = data.length
|
|
972
969
|
dataVersion.value++
|
|
970
|
+
symbolError.value = data.length === 0
|
|
971
|
+
})
|
|
972
|
+
|
|
973
|
+
const unsubscribeDataLoading = ctrl.dataLoading.subscribe(() => {
|
|
974
|
+
symbolLoading.value = ctrl.dataLoading.peek()
|
|
973
975
|
})
|
|
974
976
|
|
|
975
977
|
const unsubscribeTheme = ctrl.theme.subscribe(() => {
|
|
@@ -1034,6 +1036,7 @@ function setupChartCallbacks(ctrl: ChartController): void {
|
|
|
1034
1036
|
onUnmounted(() => {
|
|
1035
1037
|
unsubscribeViewport()
|
|
1036
1038
|
unsubscribeData()
|
|
1039
|
+
unsubscribeDataLoading()
|
|
1037
1040
|
unsubscribePaneRatios()
|
|
1038
1041
|
unsubscribePaneLayout()
|
|
1039
1042
|
unsubscribeTheme()
|
|
@@ -1048,13 +1051,6 @@ function applyInitialSettings(ctrl: ChartController): void {
|
|
|
1048
1051
|
chartSettings.value = initialSettings
|
|
1049
1052
|
applyThemeFromSettings(ctrl, initialSettings.theme as string)
|
|
1050
1053
|
ctrl.updateSettingsFacade(initialSettings)
|
|
1051
|
-
|
|
1052
|
-
if (initialSettings.performanceTest10kKlines) {
|
|
1053
|
-
const testData = generate10kKLineData()
|
|
1054
|
-
console.time('updateData-10k')
|
|
1055
|
-
ctrl.updateData(testData)
|
|
1056
|
-
console.timeEnd('updateData-10k')
|
|
1057
|
-
}
|
|
1058
1054
|
}
|
|
1059
1055
|
|
|
1060
1056
|
function setupDrawingController(ctrl: ChartController): void {
|
|
@@ -1082,7 +1078,7 @@ function setupInteractionCallbacks(ctrl: ChartController): void {
|
|
|
1082
1078
|
}
|
|
1083
1079
|
|
|
1084
1080
|
function setupSemanticController(ctrl: ChartController): void {
|
|
1085
|
-
|
|
1081
|
+
ctrl.setDataFetcher(props.dataFetcher)
|
|
1086
1082
|
semanticController.value = new SemanticChartController(ctrl)
|
|
1087
1083
|
|
|
1088
1084
|
semanticController.value.on('config:error', (error) => {
|
|
@@ -1095,21 +1091,12 @@ function setupSemanticController(ctrl: ChartController): void {
|
|
|
1095
1091
|
syncSubPanesFromChart()
|
|
1096
1092
|
nextTick(() => scrollToRight())
|
|
1097
1093
|
})
|
|
1098
|
-
//
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
console.error('Semantic config apply failed:', result.errors)
|
|
1105
|
-
}
|
|
1106
|
-
} else {
|
|
1107
|
-
semanticController.value.applyConfig(props.semanticConfig).then((result) => {
|
|
1108
|
-
if (result && !result.success) {
|
|
1109
|
-
console.error('Semantic config apply failed:', result.errors)
|
|
1110
|
-
}
|
|
1111
|
-
})
|
|
1112
|
-
}
|
|
1094
|
+
// 暂时断开语义化配置加载,由搜索结果驱动
|
|
1095
|
+
// semanticController.value.applyConfig(props.semanticConfig).then((result) => {
|
|
1096
|
+
// if (result && !result.success) {
|
|
1097
|
+
// console.error('Semantic config apply failed:', result.errors)
|
|
1098
|
+
// }
|
|
1099
|
+
// })
|
|
1113
1100
|
}
|
|
1114
1101
|
|
|
1115
1102
|
onMounted(() => {
|