@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@363045841yyt/klinechart",
3
- "version": "0.8.0",
3
+ "version": "0.8.1-alpha.2",
4
4
  "description": "Vue 3 bindings for @363045841yyt/klinechart-core. Idiomatic composables, SFC components.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,11 +1,14 @@
1
1
  <template>
2
2
  <div ref="chartWrapperRef" class="chart-wrapper" :data-theme="chartTheme" :style="themeCssVars">
3
- <TopToolbar
4
- :symbol="semanticConfig.data.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 { resolveThemeColors, themeToCssVars, lightTheme, darkTheme, type ColorPresetSettings } from '@363045841yyt/klinechart-core'
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)?.[chartTheme.value]
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
- if (settings.performanceTest10kKlines) {
303
- const testData = generate10kKLineData()
304
- console.time('updateData-10k')
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', 'BOLL', 'EXPMA', 'ENE', 'WMA', 'DEMA', 'TEMA', 'HMA',
740
- 'KAMA', 'SAR', 'SUPERTREND', 'KELTNER', 'DONCHIAN', 'ICHIMOKU',
741
- 'PIVOT', 'FIB', 'STRUCTURE', 'ZONES',
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' || indicatorId === 'BOLL' ||
776
- indicatorId === 'EXPMA' || indicatorId === 'ENE'
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
- __setDataFetcher(props.dataFetcher)
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
- if (chartSettings.value.performanceTest10kKlines) {
1100
- // 10k 性能测试模式:数据由外部(applyInitialSettings)提供,
1101
- // 语义控制器只注册指标和标记,不 fetch/updateData,避免数据跳变
1102
- const result = semanticController.value.applyIndicatorsOnly(props.semanticConfig)
1103
- if (result && !result.success) {
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(() => {