@363045841yyt/klinechart 0.8.0 → 0.8.1-alpha.1

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.1",
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,37 @@ 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
+ symbolLoading.value = true
222
+ symbolError.value = false
223
+ currentSymbol.value = item.code
224
+ controller.value?.setSymbols([
225
+ {
226
+ symbol: item.code,
227
+ exchange: item.exchange,
228
+ period: kLineLevel.value,
229
+ source: item.source,
230
+ startDate: props.semanticConfig.data.startDate,
231
+ endDate: props.semanticConfig.data.endDate,
232
+ adjust: props.semanticConfig.data.adjust,
233
+ },
234
+ ])
235
+ }
236
+
209
237
  const containerRef = ref<HTMLDivElement | null>(null)
210
238
  const chartMainRef = ref<HTMLDivElement | null>(null)
211
239
  const chartWrapperRef = ref<HTMLDivElement | null>(null)
@@ -258,7 +286,9 @@ const tooltipColors = computed(() => {
258
286
 
259
287
  const themeCssVars = computed(() => {
260
288
  const theme = chartTheme.value === 'dark' ? darkTheme : lightTheme
261
- const overrides = (chartSettings.value.colorPresetSettings as ColorPresetSettings | undefined)?.[chartTheme.value]
289
+ const overrides = (chartSettings.value.colorPresetSettings as ColorPresetSettings | undefined)?.[
290
+ chartTheme.value
291
+ ]
262
292
  if (overrides && Object.keys(overrides).length > 0) {
263
293
  return themeToCssVars({ ...theme, colors: { ...theme.colors, ...overrides } })
264
294
  }
@@ -299,55 +329,10 @@ function handleSettingsChange(settings: ChartSettings) {
299
329
  applyThemeFromSettings(controller.value, settings.theme as string)
300
330
  controller.value?.updateSettingsFacade(settings)
301
331
 
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
332
+ controller.value?.setDataFetcher(props.dataFetcher)
333
+ if (semanticController.value && props.semanticConfig) {
334
+ semanticController.value.applyConfig(props.semanticConfig)
348
335
  }
349
-
350
- return data
351
336
  }
352
337
 
353
338
  function measureTooltipSize(el: HTMLDivElement, minWidth: number, minHeight: number) {
@@ -736,9 +721,24 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
736
721
  if (!c) return
737
722
 
738
723
  const mainIndicatorIds = [
739
- 'MA', 'BOLL', 'EXPMA', 'ENE', 'WMA', 'DEMA', 'TEMA', 'HMA',
740
- 'KAMA', 'SAR', 'SUPERTREND', 'KELTNER', 'DONCHIAN', 'ICHIMOKU',
741
- 'PIVOT', 'FIB', 'STRUCTURE', 'ZONES',
724
+ 'MA',
725
+ 'BOLL',
726
+ 'EXPMA',
727
+ 'ENE',
728
+ 'WMA',
729
+ 'DEMA',
730
+ 'TEMA',
731
+ 'HMA',
732
+ 'KAMA',
733
+ 'SAR',
734
+ 'SUPERTREND',
735
+ 'KELTNER',
736
+ 'DONCHIAN',
737
+ 'ICHIMOKU',
738
+ 'PIVOT',
739
+ 'FIB',
740
+ 'STRUCTURE',
741
+ 'ZONES',
742
742
  ]
743
743
  if (mainIndicatorIds.includes(indicatorId)) {
744
744
  const existingIndicator = mainActiveIndicators.value.find((id) => id === indicatorId)
@@ -772,8 +772,10 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
772
772
 
773
773
  function handleUpdateParams(indicatorId: string, params: Record<string, unknown>) {
774
774
  if (
775
- indicatorId === 'MA' || indicatorId === 'BOLL' ||
776
- indicatorId === 'EXPMA' || indicatorId === 'ENE'
775
+ indicatorId === 'MA' ||
776
+ indicatorId === 'BOLL' ||
777
+ indicatorId === 'EXPMA' ||
778
+ indicatorId === 'ENE'
777
779
  ) {
778
780
  controller.value?.updateIndicatorParams(indicatorId, params)
779
781
  return
@@ -942,11 +944,7 @@ function setupChartCallbacks(ctrl: ChartController): void {
942
944
  if (viewWidth.value !== vp.plotWidth) {
943
945
  viewWidth.value = vp.plotWidth
944
946
  }
945
- if (
946
- zoomLevel.value !== vp.zoomLevel ||
947
- kWidth.value !== vp.kWidth ||
948
- kGap.value !== vp.kGap
949
- ) {
947
+ if (zoomLevel.value !== vp.zoomLevel || kWidth.value !== vp.kWidth || kGap.value !== vp.kGap) {
950
948
  zoomLevel.value = vp.zoomLevel
951
949
  kWidth.value = vp.kWidth
952
950
  kGap.value = vp.kGap
@@ -970,6 +968,8 @@ function setupChartCallbacks(ctrl: ChartController): void {
970
968
  const data = ctrl.data.peek()
971
969
  dataLength.value = data.length
972
970
  dataVersion.value++
971
+ symbolLoading.value = false
972
+ symbolError.value = data.length === 0
973
973
  })
974
974
 
975
975
  const unsubscribeTheme = ctrl.theme.subscribe(() => {
@@ -1048,13 +1048,6 @@ function applyInitialSettings(ctrl: ChartController): void {
1048
1048
  chartSettings.value = initialSettings
1049
1049
  applyThemeFromSettings(ctrl, initialSettings.theme as string)
1050
1050
  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
1051
  }
1059
1052
 
1060
1053
  function setupDrawingController(ctrl: ChartController): void {
@@ -1082,7 +1075,7 @@ function setupInteractionCallbacks(ctrl: ChartController): void {
1082
1075
  }
1083
1076
 
1084
1077
  function setupSemanticController(ctrl: ChartController): void {
1085
- __setDataFetcher(props.dataFetcher)
1078
+ ctrl.setDataFetcher(props.dataFetcher)
1086
1079
  semanticController.value = new SemanticChartController(ctrl)
1087
1080
 
1088
1081
  semanticController.value.on('config:error', (error) => {
@@ -1095,21 +1088,12 @@ function setupSemanticController(ctrl: ChartController): void {
1095
1088
  syncSubPanesFromChart()
1096
1089
  nextTick(() => scrollToRight())
1097
1090
  })
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
- }
1091
+ // 暂时断开语义化配置加载,由搜索结果驱动
1092
+ // semanticController.value.applyConfig(props.semanticConfig).then((result) => {
1093
+ // if (result && !result.success) {
1094
+ // console.error('Semantic config apply failed:', result.errors)
1095
+ // }
1096
+ // })
1113
1097
  }
1114
1098
 
1115
1099
  onMounted(() => {