@363045841yyt/klinechart 0.8.4 → 0.8.6

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.
Files changed (69) hide show
  1. package/README.md +6 -1
  2. package/dist/components/BaseModal.vue.d.ts +54 -0
  3. package/dist/components/BaseModal.vue.d.ts.map +1 -0
  4. package/dist/components/BatchStockDialog.vue.d.ts +13 -0
  5. package/dist/components/BatchStockDialog.vue.d.ts.map +1 -0
  6. package/dist/components/ChartSettingsDialog.vue.d.ts.map +1 -1
  7. package/dist/components/ColorPresetPanel.vue.d.ts +4 -1
  8. package/dist/components/ColorPresetPanel.vue.d.ts.map +1 -1
  9. package/dist/components/CompareSymbolSelector.vue.d.ts.map +1 -1
  10. package/dist/components/DrawingStyleToolbar.vue.d.ts.map +1 -1
  11. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  12. package/dist/components/ExportProgressDialog.vue.d.ts +15 -0
  13. package/dist/components/ExportProgressDialog.vue.d.ts.map +1 -0
  14. package/dist/components/IndicatorParams.vue.d.ts.map +1 -1
  15. package/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
  16. package/dist/components/KLineChart.vue.d.ts +5 -9
  17. package/dist/components/KLineChart.vue.d.ts.map +1 -1
  18. package/dist/components/LeftToolbar.vue.d.ts.map +1 -1
  19. package/dist/components/RangeSelectionExport.vue.d.ts +23 -0
  20. package/dist/components/RangeSelectionExport.vue.d.ts.map +1 -0
  21. package/dist/components/SymbolSelector.vue.d.ts.map +1 -1
  22. package/dist/components/TopToolbar.vue.d.ts.map +1 -1
  23. package/dist/components/common/CanvasToolbar.vue.d.ts +14 -0
  24. package/dist/components/common/CanvasToolbar.vue.d.ts.map +1 -0
  25. package/dist/components/common/CanvasToolbarStack.vue.d.ts +14 -0
  26. package/dist/components/common/CanvasToolbarStack.vue.d.ts.map +1 -0
  27. package/dist/composables/chart/useChartTheme.d.ts +329 -0
  28. package/dist/composables/chart/useChartTheme.d.ts.map +1 -0
  29. package/dist/composables/chart/useDrawingManager.d.ts +86 -0
  30. package/dist/composables/chart/useDrawingManager.d.ts.map +1 -0
  31. package/dist/composables/chart/useIndicatorManager.d.ts +38 -0
  32. package/dist/composables/chart/useIndicatorManager.d.ts.map +1 -0
  33. package/dist/composables/chart/useRangeSelection.d.ts +66 -0
  34. package/dist/composables/chart/useRangeSelection.d.ts.map +1 -0
  35. package/dist/composables/useTeleportedPopup.d.ts +8 -0
  36. package/dist/composables/useTeleportedPopup.d.ts.map +1 -0
  37. package/dist/index.cjs +9 -2
  38. package/dist/index.css +1 -1
  39. package/dist/index.js +2149 -1409
  40. package/dist/tools/calcRangeOverlayPixel.d.ts +15 -0
  41. package/dist/tools/calcRangeOverlayPixel.d.ts.map +1 -0
  42. package/dist/tools/getKLineIndexByTimestamp.d.ts +4 -0
  43. package/dist/tools/getKLineIndexByTimestamp.d.ts.map +1 -0
  44. package/dist/web-component.d.ts.map +1 -1
  45. package/package.json +1 -1
  46. package/src/components/BaseModal.vue +292 -0
  47. package/src/components/BatchStockDialog.vue +128 -0
  48. package/src/components/ChartSettingsDialog.vue +248 -405
  49. package/src/components/ColorPresetPanel.vue +58 -106
  50. package/src/components/CompareSymbolSelector.vue +37 -10
  51. package/src/components/DrawingStyleToolbar.vue +33 -72
  52. package/src/components/Dropdown.vue +42 -19
  53. package/src/components/ExportProgressDialog.vue +118 -0
  54. package/src/components/IndicatorParams.vue +194 -321
  55. package/src/components/IndicatorSelector.vue +188 -405
  56. package/src/components/KLineChart.vue +228 -403
  57. package/src/components/LeftToolbar.vue +3 -2
  58. package/src/components/RangeSelectionExport.vue +117 -0
  59. package/src/components/SymbolSelector.vue +37 -10
  60. package/src/components/TopToolbar.vue +55 -2
  61. package/src/components/common/CanvasToolbar.vue +70 -0
  62. package/src/components/common/CanvasToolbarStack.vue +32 -0
  63. package/src/composables/chart/useChartTheme.ts +86 -0
  64. package/src/composables/chart/useDrawingManager.ts +67 -0
  65. package/src/composables/chart/useIndicatorManager.ts +307 -0
  66. package/src/composables/chart/useRangeSelection.ts +424 -0
  67. package/src/composables/useTeleportedPopup.ts +46 -0
  68. package/src/tools/calcRangeOverlayPixel.ts +28 -0
  69. package/src/tools/getKLineIndexByTimestamp.ts +40 -0
@@ -0,0 +1,15 @@
1
+ import { ChartController } from '@363045841yyt/klinechart-core/controllers';
2
+ export interface Bounds {
3
+ start: number;
4
+ end: number;
5
+ }
6
+ export declare function calcRangeOverlayPixel(bounds: Bounds, controller: ChartController, container: HTMLElement, viewport: {
7
+ scrollLeft: number;
8
+ plotWidth: number;
9
+ plotHeight: number;
10
+ }): {
11
+ left: number;
12
+ width: number;
13
+ height: number;
14
+ };
15
+ //# sourceMappingURL=calcRangeOverlayPixel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calcRangeOverlayPixel.d.ts","sourceRoot":"","sources":["../../src/tools/calcRangeOverlayPixel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAA;AAEhF,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAejD"}
@@ -0,0 +1,4 @@
1
+ import { KLineData } from '@363045841yyt/klinechart-core/controllers';
2
+ export declare function getKLineIndexByTimestamp(data: ReadonlyArray<KLineData>, timestamp: number): number | null;
3
+ export declare function findNearestKLineIndex(data: ReadonlyArray<KLineData>, timestamp: number, direction: 'left' | 'right'): number | null;
4
+ //# sourceMappingURL=getKLineIndexByTimestamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getKLineIndexByTimestamp.d.ts","sourceRoot":"","sources":["../../src/tools/getKLineIndexByTimestamp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAkB1E,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,EAC9B,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAIf;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,OAAO,GAC1B,MAAM,GAAG,IAAI,CAQf"}
@@ -1 +1 @@
1
- {"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;aAUo0zC,CAAC;kBAAyB,CAAC;;;;;iBAAsH,CAAC;gBAAc,CAAC;;;iBAAuD,CAAC;gBAAc,CAAC;;qBAAgC,CAAC;;EARlm0C,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;aAUojnC,CAAC;kBAAyB,CAAC;;;;;iBAAsH,CAAC;gBAAc,CAAC;;;iBAAuD,CAAC;gBAAc,CAAC;;qBAAgC,CAAC;;EARl1nC,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@363045841yyt/klinechart",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "description": "Vue 3 bindings for @363045841yyt/klinechart-core. Idiomatic composables, SFC components.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,292 @@
1
+ <template>
2
+ <Teleport :to="teleportTarget">
3
+ <Transition name="overlay">
4
+ <div
5
+ v-if="show"
6
+ class="base-overlay"
7
+ :style="{ zIndex, padding: overlayPadding }"
8
+ @click="closeOnOverlay ? emit('close') : undefined"
9
+ >
10
+ <Transition :name="modalTransitionName">
11
+ <div
12
+ class="base-modal"
13
+ :style="modalStyle"
14
+ @click.stop
15
+ >
16
+ <div v-if="$slots.header || title" class="base-header">
17
+ <slot name="header">
18
+ <div class="base-header-left">
19
+ <span class="base-title">{{ title }}</span>
20
+ <span v-if="subtitle" class="base-subtitle">{{ subtitle }}</span>
21
+ </div>
22
+ </slot>
23
+ <div v-if="showClose" class="base-header-right">
24
+ <slot name="header-extra" />
25
+ <button class="base-close-btn" @click="emit('close')">
26
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
27
+ <path d="M18 6L6 18M6 6l12 12" />
28
+ </svg>
29
+ </button>
30
+ </div>
31
+ </div>
32
+
33
+ <div v-if="$slots.subheader" class="base-subheader">
34
+ <slot name="subheader" />
35
+ </div>
36
+
37
+ <div class="base-body" :style="{ padding: bodyPadding }">
38
+ <slot />
39
+ </div>
40
+
41
+ <div v-if="$slots.footer" class="base-footer" :style="{ justifyContent: footerAlign }">
42
+ <slot name="footer" />
43
+ </div>
44
+ </div>
45
+ </Transition>
46
+ </div>
47
+ </Transition>
48
+ </Teleport>
49
+ </template>
50
+
51
+ <script setup lang="ts">
52
+ import { computed } from 'vue'
53
+ import { useFullscreenTeleportTarget } from '../composables/useFullscreenTeleportTarget'
54
+
55
+ const props = withDefaults(
56
+ defineProps<{
57
+ show: boolean
58
+ title?: string
59
+ subtitle?: string
60
+ zIndex?: number
61
+ width?: string
62
+ maxWidth?: string
63
+ maxHeight?: string
64
+ overlayPadding?: string
65
+ bodyPadding?: string
66
+ footerAlign?: 'flex-end' | 'center' | 'flex-start' | 'space-between'
67
+ closeOnOverlay?: boolean
68
+ showClose?: boolean
69
+ transitionVariant?: 'default' | 'compact'
70
+ }>(),
71
+ {
72
+ title: '',
73
+ subtitle: '',
74
+ zIndex: 1000,
75
+ width: 'min(92vw, 400px)',
76
+ maxWidth: '',
77
+ maxHeight: 'min(600px, calc(100vh - 48px))',
78
+ overlayPadding: '24px',
79
+ bodyPadding: '16px 20px',
80
+ footerAlign: 'flex-end',
81
+ closeOnOverlay: true,
82
+ showClose: true,
83
+ transitionVariant: 'default',
84
+ },
85
+ )
86
+
87
+ const emit = defineEmits<{
88
+ close: []
89
+ }>()
90
+
91
+ const teleportTarget = useFullscreenTeleportTarget()
92
+
93
+ const modalTransitionName = computed(() =>
94
+ props.transitionVariant === 'compact' ? 'modal-compact' : 'modal',
95
+ )
96
+
97
+ const modalStyle = computed(() => ({
98
+ width: props.width,
99
+ maxWidth: props.maxWidth || undefined,
100
+ maxHeight: props.maxHeight,
101
+ }))
102
+ </script>
103
+
104
+ <style scoped>
105
+ .base-overlay {
106
+ position: fixed;
107
+ inset: 0;
108
+ background: rgba(0, 0, 0, 0.3);
109
+ backdrop-filter: blur(4px);
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ }
114
+
115
+ .base-modal {
116
+ background: var(--klc-color-background);
117
+ border: 1px solid var(--klc-color-border-button);
118
+ border-radius: 10px;
119
+ box-shadow: 0 18px 48px rgba(0, 0, 0, 0.15);
120
+ overflow: hidden;
121
+ display: flex;
122
+ flex-direction: column;
123
+ }
124
+
125
+ .base-header {
126
+ display: flex;
127
+ justify-content: space-between;
128
+ align-items: center;
129
+ padding: 14px 18px 14px 20px;
130
+ background: var(--klc-color-background);
131
+ border-bottom: 1px solid var(--klc-color-grid-major);
132
+ flex-shrink: 0;
133
+ gap: 12px;
134
+ }
135
+
136
+ .base-header-left {
137
+ display: flex;
138
+ align-items: baseline;
139
+ gap: 8px;
140
+ min-width: 0;
141
+ }
142
+
143
+ .base-title {
144
+ font-size: 15px;
145
+ font-weight: 600;
146
+ color: var(--klc-color-foreground);
147
+ line-height: 1.35;
148
+ }
149
+
150
+ .base-subtitle {
151
+ font-size: 11px;
152
+ color: var(--klc-color-axis-text);
153
+ line-height: 1.3;
154
+ white-space: nowrap;
155
+ }
156
+
157
+ .base-header-right {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 8px;
161
+ flex-shrink: 0;
162
+ }
163
+
164
+ .base-close-btn {
165
+ background: var(--klc-color-background);
166
+ border: 1px solid var(--klc-color-border-button);
167
+ border-radius: 8px;
168
+ width: 32px;
169
+ height: 32px;
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: center;
173
+ cursor: pointer;
174
+ color: var(--klc-color-axis-text);
175
+ transition: background 0.15s, color 0.15s, border-color 0.15s;
176
+ padding: 0;
177
+ }
178
+
179
+ .base-close-btn:hover {
180
+ background: var(--klc-color-tag-bg-hover);
181
+ color: var(--klc-color-foreground);
182
+ border-color: var(--klc-color-axis-line);
183
+ }
184
+
185
+ .base-close-btn svg {
186
+ width: 14px;
187
+ height: 14px;
188
+ }
189
+
190
+ .base-subheader {
191
+ flex-shrink: 0;
192
+ padding: 16px 20px;
193
+ background: var(--klc-color-background);
194
+ border-bottom: 1px solid var(--klc-color-grid-major);
195
+ }
196
+
197
+ .base-body {
198
+ flex: 1;
199
+ min-height: 0;
200
+ overflow-y: auto;
201
+ background: var(--klc-color-background);
202
+ }
203
+
204
+ .base-body::-webkit-scrollbar {
205
+ width: 8px;
206
+ }
207
+
208
+ .base-body::-webkit-scrollbar-track {
209
+ background: var(--klc-color-background);
210
+ }
211
+
212
+ .base-body::-webkit-scrollbar-thumb {
213
+ background: var(--klc-color-axis-line);
214
+ border: 2px solid var(--klc-color-background);
215
+ border-radius: 999px;
216
+ }
217
+
218
+ .base-footer {
219
+ display: flex;
220
+ align-items: center;
221
+ justify-content: flex-end;
222
+ gap: 8px;
223
+ padding: 12px 20px;
224
+ background: var(--klc-color-background);
225
+ border-top: 1px solid var(--klc-color-grid-major);
226
+ flex-shrink: 0;
227
+ }
228
+
229
+ /* ── Overlay transition ── */
230
+ .overlay-enter-active,
231
+ .overlay-leave-active {
232
+ transition: opacity 0.2s ease;
233
+ }
234
+
235
+ .overlay-enter-from,
236
+ .overlay-leave-to {
237
+ opacity: 0;
238
+ }
239
+
240
+ /* ── Modal transition (default variant) ── */
241
+ .modal-enter-active {
242
+ transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
243
+ }
244
+
245
+ .modal-leave-active {
246
+ transition: all 0.16s ease-in;
247
+ }
248
+
249
+ .modal-enter-from {
250
+ opacity: 0;
251
+ transform: scale(0.96) translateY(-10px);
252
+ }
253
+
254
+ .modal-leave-to {
255
+ opacity: 0;
256
+ transform: scale(0.98) translateY(8px);
257
+ }
258
+
259
+ /* ── Modal transition (compact variant) ── */
260
+ .modal-compact-enter-active {
261
+ transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
262
+ }
263
+
264
+ .modal-compact-leave-active {
265
+ transition: all 0.16s ease-in;
266
+ }
267
+
268
+ .modal-compact-enter-from {
269
+ opacity: 0;
270
+ transform: scale(0.88) translateY(-16px);
271
+ }
272
+
273
+ .modal-compact-leave-to {
274
+ opacity: 0;
275
+ transform: scale(0.94) translateY(8px);
276
+ }
277
+
278
+ /* ── Responsive ── */
279
+ @media (max-width: 480px) {
280
+ .base-overlay {
281
+ padding: 12px;
282
+ align-items: flex-end;
283
+ }
284
+
285
+ .base-modal {
286
+ min-width: 0;
287
+ width: 100% !important;
288
+ max-height: calc(100vh - 24px);
289
+ border-radius: 10px;
290
+ }
291
+ }
292
+ </style>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <BaseModal title="批量设置股票代码" :show="show" @close="emit('close')">
3
+ <textarea
4
+ v-model="codesText"
5
+ class="batch-textarea"
6
+ placeholder="每行一个股票代码,导出时会将所选区间内这些品种的数据一并导出&#10;例如:&#10;000001&#10;600036&#10;002415"
7
+ rows="8"
8
+ spellcheck="false"
9
+ />
10
+ <template #footer>
11
+ <button class="batch-btn batch-btn--cancel" @click="emit('close')">取消</button>
12
+ <button class="batch-btn batch-btn--confirm" @click="onApply">应用</button>
13
+ </template>
14
+ </BaseModal>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { ref, computed } from 'vue'
19
+ import BaseModal from './BaseModal.vue'
20
+
21
+ const props = defineProps<{
22
+ show: boolean
23
+ }>()
24
+
25
+ const emit = defineEmits<{
26
+ close: []
27
+ apply: [codes: string[]]
28
+ }>()
29
+
30
+ const codes = ref<string[]>([])
31
+
32
+ const codesText = computed({
33
+ get: () => codes.value.join('\n'),
34
+ set: (val: string) => {
35
+ codes.value = val
36
+ .split('\n')
37
+ .map((s) => s.trim())
38
+ .filter(Boolean)
39
+ },
40
+ })
41
+
42
+ function onApply() {
43
+ if (codes.value.length === 0) return
44
+ emit('apply', codes.value)
45
+ emit('close')
46
+ }
47
+ </script>
48
+
49
+ <style scoped>
50
+ .batch-textarea {
51
+ width: 100%;
52
+ min-height: 160px;
53
+ max-height: 100%;
54
+ padding: 10px 12px;
55
+ border: 1px solid var(--klc-color-border-button);
56
+ border-radius: 6px;
57
+ background: var(--klc-color-background);
58
+ color: var(--klc-color-foreground);
59
+ font-size: 13px;
60
+ font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
61
+ line-height: 1.5;
62
+ resize: vertical;
63
+ outline: none;
64
+ transition: border-color 0.15s;
65
+ box-sizing: border-box;
66
+ }
67
+
68
+ .batch-textarea:focus {
69
+ border-color: var(--klc-color-axis-text);
70
+ }
71
+
72
+ .batch-textarea::placeholder {
73
+ color: var(--klc-color-axis-text);
74
+ opacity: 0.5;
75
+ }
76
+
77
+ .batch-btn {
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ min-width: 68px;
82
+ height: 32px;
83
+ padding: 0 14px;
84
+ border-radius: 7px;
85
+ font-size: 13px;
86
+ font-weight: 500;
87
+ cursor: pointer;
88
+ border: 1px solid transparent;
89
+ transition:
90
+ background 0.15s,
91
+ border-color 0.15s,
92
+ color 0.15s,
93
+ box-shadow 0.15s,
94
+ transform 0.15s;
95
+ line-height: 1;
96
+ white-space: nowrap;
97
+ }
98
+
99
+ .batch-btn--cancel {
100
+ background: transparent;
101
+ border-color: var(--klc-color-axis-line);
102
+ color: var(--klc-color-axis-text);
103
+ }
104
+
105
+ .batch-btn--cancel:hover {
106
+ background: var(--klc-color-tag-bg-hover);
107
+ color: var(--klc-color-foreground);
108
+ border-color: var(--klc-color-axis-text);
109
+ }
110
+
111
+ .batch-btn--confirm {
112
+ background: var(--klc-color-foreground);
113
+ border-color: var(--klc-color-foreground);
114
+ color: var(--klc-color-background);
115
+ }
116
+
117
+ .batch-btn--confirm:hover {
118
+ background: var(--klc-color-foreground);
119
+ border-color: var(--klc-color-foreground);
120
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
121
+ transform: translateY(-1px);
122
+ }
123
+
124
+ .batch-btn--confirm:active {
125
+ transform: translateY(0);
126
+ box-shadow: none;
127
+ }
128
+ </style>