@363045841yyt/klinechart 0.8.1-alpha.4 → 0.8.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.1-alpha.4",
3
+ "version": "0.8.1",
4
4
  "description": "Vue 3 bindings for @363045841yyt/klinechart-core. Idiomatic composables, SFC components.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,6 +11,7 @@
11
11
  >
12
12
  <span class="compare-chip__icon" aria-hidden="true">+</span>
13
13
  <span class="compare-chip__text">比较商品</span>
14
+ <span v-if="comparisonLoading" class="compare-chip__spinner" />
14
15
  <span v-if="selected.length > 0" class="compare-chip__badge">{{ selected.length }}</span>
15
16
  </button>
16
17
  <Transition name="symbol-popover">
@@ -65,6 +66,10 @@
65
66
  :key="item.code"
66
67
  class="compare-selected__item"
67
68
  >
69
+ <span
70
+ class="compare-selected__color"
71
+ :style="{ background: comparisonColors?.get(item.code) ?? '#888' }"
72
+ />
68
73
  <span class="compare-selected__code">{{ item.code }}</span>
69
74
  <span class="compare-selected__desc">{{ item.description }}</span>
70
75
  <button
@@ -140,6 +145,8 @@ import type { SymbolItem } from './SymbolSelector.vue'
140
145
  const props = withDefaults(defineProps<{
141
146
  symbols: SymbolItem[]
142
147
  selected?: string[]
148
+ comparisonColors?: Map<string, string>
149
+ comparisonLoading?: boolean
143
150
  }>(), {
144
151
  selected: () => [],
145
152
  })
@@ -280,6 +287,20 @@ onBeforeUnmount(() => document.removeEventListener('mousedown', onDocumentClick)
280
287
  line-height: 1;
281
288
  }
282
289
 
290
+ .compare-chip__spinner {
291
+ display: inline-block;
292
+ width: 12px;
293
+ height: 12px;
294
+ border: 2px solid var(--klc-color-axis-text);
295
+ border-top-color: transparent;
296
+ border-radius: 50%;
297
+ animation: compare-spin 0.6s linear infinite;
298
+ }
299
+
300
+ @keyframes compare-spin {
301
+ to { transform: rotate(360deg); }
302
+ }
303
+
283
304
  .compare-popover {
284
305
  position: absolute;
285
306
  top: calc(100% + 8px);
@@ -406,6 +427,14 @@ onBeforeUnmount(() => document.removeEventListener('mousedown', onDocumentClick)
406
427
  line-height: 1.3;
407
428
  }
408
429
 
430
+ .compare-selected__color {
431
+ display: inline-block;
432
+ width: 8px;
433
+ height: 8px;
434
+ border-radius: 50%;
435
+ flex-shrink: 0;
436
+ }
437
+
409
438
  .compare-selected__code {
410
439
  font-weight: 600;
411
440
  color: var(--klc-color-foreground);
@@ -6,6 +6,8 @@
6
6
  :symbol-loading="symbolLoading"
7
7
  :symbol-error="symbolError"
8
8
  :overlay-symbols="overlaySymbols"
9
+ :comparison-colors="comparisonColorsMap"
10
+ :comparison-loading="comparisonLoading"
9
11
  @add-overlay-symbol="onAddOverlaySymbol"
10
12
  @remove-overlay-symbol="onRemoveOverlaySymbol"
11
13
  @k-line-level-change="onKLineLevelChange"
@@ -152,6 +154,7 @@ import {
152
154
  getRegisteredIndicatorDefinitions,
153
155
  } from '@363045841yyt/klinechart-core/indicators'
154
156
  import type { DrawingObject, DrawingStyle } from '@363045841yyt/klinechart-core/plugin'
157
+ import { SETTINGS_STORAGE_KEY } from '@363045841yyt/klinechart-core/config'
155
158
  import type { ChartSettings } from '@363045841yyt/klinechart-core/config'
156
159
  import {
157
160
  resolveThemeColors,
@@ -235,13 +238,13 @@ function onAddOverlaySymbol(item: SymbolItem) {
235
238
  overlaySymbolItems.value = [...overlaySymbolItems.value, item]
236
239
  overlaySymbols.value = overlaySymbolItems.value.map((symbol) => symbol.code)
237
240
  forcePercentAxis()
238
- syncSymbolsToController()
241
+ controller.value?.addComparisonSymbol(toSymbolSpec(item))
239
242
  }
240
243
 
241
244
  function onRemoveOverlaySymbol(code: string) {
242
245
  overlaySymbolItems.value = overlaySymbolItems.value.filter((item) => item.code !== code)
243
246
  overlaySymbols.value = overlaySymbolItems.value.map((symbol) => symbol.code)
244
- syncSymbolsToController()
247
+ controller.value?.removeComparisonSymbol(code)
245
248
  }
246
249
 
247
250
  function toSymbolSpec(item: SymbolItem): SymbolSpec {
@@ -269,6 +272,9 @@ function forcePercentAxis() {
269
272
  const nextSettings = { ...chartSettings.value, axisType: 'percent' as const }
270
273
  chartSettings.value = nextSettings
271
274
  controller.value?.updateSettingsFacade(nextSettings)
275
+ try {
276
+ localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(nextSettings))
277
+ } catch { /* quota exceeded */ }
272
278
  }
273
279
 
274
280
  const containerRef = ref<HTMLDivElement | null>(null)
@@ -296,6 +302,8 @@ const viewWidth = ref(0)
296
302
  const paneRatios = ref<Record<string, number>>({})
297
303
  const selectedDrawingId = ref<string | null>(null)
298
304
  const drawings = ref<DrawingObject[]>([])
305
+ const comparisonColorsMap = ref<Map<string, string>>(new Map())
306
+ const comparisonLoading = ref(false)
299
307
 
300
308
  // 初始化 kWidth / kGap(与 Chart 引擎 zoom→物理值 转换一致)
301
309
  const initZoom = zoomLevel.value
@@ -983,6 +991,14 @@ function setupChartCallbacks(ctrl: ChartController): void {
983
991
  indicatorParams.value = nextParams
984
992
  })
985
993
 
994
+ const unsubscribeComparisonColors = ctrl.comparisonColors.subscribe(() => {
995
+ comparisonColorsMap.value = new Map(ctrl.comparisonColors.peek())
996
+ })
997
+
998
+ const unsubscribeComparisonLoading = ctrl.comparisonLoading.subscribe(() => {
999
+ comparisonLoading.value = ctrl.comparisonLoading.peek()
1000
+ })
1001
+
986
1002
  onUnmounted(() => {
987
1003
  unsubscribeViewport()
988
1004
  unsubscribeData()
@@ -992,6 +1008,8 @@ function setupChartCallbacks(ctrl: ChartController): void {
992
1008
  unsubscribeTheme()
993
1009
  unsubscribeIndicators()
994
1010
  unsubscribeSubPanes()
1011
+ unsubscribeComparisonColors()
1012
+ unsubscribeComparisonLoading()
995
1013
  autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
996
1014
  })
997
1015
  }
@@ -4,12 +4,12 @@
4
4
  type="button"
5
5
  class="symbol-chip"
6
6
  :class="{ 'is-open': showPopup }"
7
- :title="symbol"
7
+ :title="displayText"
8
8
  :aria-expanded="showPopup"
9
9
  aria-haspopup="dialog"
10
10
  @click="togglePopup"
11
11
  >
12
- <span class="symbol-chip__code">{{ symbol }}</span>
12
+ <span class="symbol-chip__code">{{ displayText }}</span>
13
13
  <span v-if="loading" class="symbol-chip__spinner" aria-hidden="true" />
14
14
  <IconTablerAlertTriangle v-else-if="error" class="symbol-chip__warn" aria-hidden="true" />
15
15
  </button>
@@ -127,6 +127,16 @@ const searchQuery = ref('')
127
127
  const searchInputRef = ref<HTMLInputElement | null>(null)
128
128
  const chipWrapRef = ref<HTMLElement | null>(null)
129
129
 
130
+ const currentSymbol = computed<SymbolItem | undefined>(() =>
131
+ props.symbols.find((s) => s.code === props.symbol),
132
+ )
133
+
134
+ const displayText = computed(() => {
135
+ const cur = currentSymbol.value
136
+ if (cur) return `${cur.code} - ${cur.description}`
137
+ return props.symbol
138
+ })
139
+
130
140
  const filteredSymbols = computed<SymbolItem[]>(() => {
131
141
  const q = searchQuery.value.trim().toLowerCase()
132
142
  if (!q) return props.symbols
@@ -186,7 +196,6 @@ watch(() => props.symbol, () => {
186
196
  display: inline-flex;
187
197
  align-items: center;
188
198
  justify-content: center;
189
- max-width: 160px;
190
199
  padding: 0 10px;
191
200
  gap: 5px;
192
201
  border: 1px solid transparent;
@@ -11,6 +11,8 @@
11
11
  <CompareSymbolSelector
12
12
  :symbols="symbolPool"
13
13
  :selected="overlaySymbols"
14
+ :comparison-colors="comparisonColors"
15
+ :comparison-loading="comparisonLoading"
14
16
  @add="emit('addOverlaySymbol', $event)"
15
17
  @remove="emit('removeOverlaySymbol', $event)"
16
18
  />
@@ -47,6 +49,8 @@ const props = defineProps<{
47
49
  symbolLoading?: boolean
48
50
  symbolError?: boolean
49
51
  overlaySymbols?: string[]
52
+ comparisonColors?: Map<string, string>
53
+ comparisonLoading?: boolean
50
54
  }>()
51
55
 
52
56
  const emit = defineEmits<{