@363045841yyt/klinechart 0.7.0 → 0.7.3-alpha.0

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 (233) hide show
  1. package/README.md +10 -6
  2. package/dist/components/DrawingStyleToolbar.vue.d.ts +28 -0
  3. package/dist/components/DrawingStyleToolbar.vue.d.ts.map +1 -0
  4. package/dist/{src/components → components}/IndicatorParams.vue.d.ts +3 -3
  5. package/dist/components/IndicatorParams.vue.d.ts.map +1 -0
  6. package/dist/{src/components → components}/IndicatorSelector.vue.d.ts +4 -4
  7. package/dist/components/IndicatorSelector.vue.d.ts.map +1 -0
  8. package/dist/components/KLineChart.vue.d.ts +63 -0
  9. package/dist/components/KLineChart.vue.d.ts.map +1 -0
  10. package/dist/components/KLineTooltip.vue.d.ts +30 -0
  11. package/dist/components/KLineTooltip.vue.d.ts.map +1 -0
  12. package/dist/{src/components → components}/LeftToolbar.vue.d.ts +3 -2
  13. package/dist/components/LeftToolbar.vue.d.ts.map +1 -0
  14. package/dist/components/MarkerTooltip.vue.d.ts +26 -0
  15. package/dist/components/MarkerTooltip.vue.d.ts.map +1 -0
  16. package/dist/components/index.d.ts +8 -0
  17. package/dist/components/index.d.ts.map +1 -0
  18. package/dist/{src/composables → composables}/useFullscreenTeleportTarget.d.ts +1 -0
  19. package/dist/composables/useFullscreenTeleportTarget.d.ts.map +1 -0
  20. package/dist/{src/debug → debug}/canvasProfiler.d.ts +1 -0
  21. package/dist/debug/canvasProfiler.d.ts.map +1 -0
  22. package/dist/index.cjs +2 -49
  23. package/dist/index.d.cts +124 -0
  24. package/dist/index.d.ts +124 -2
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +1470 -16916
  27. package/dist/klinechart.css +1 -1
  28. package/dist/version.d.ts +3 -0
  29. package/dist/version.d.ts.map +1 -0
  30. package/package.json +52 -81
  31. package/src/__tests__/_mockController.ts +192 -0
  32. package/src/__tests__/contract.test.ts +132 -0
  33. package/src/components/DrawingStyleToolbar.vue +199 -0
  34. package/src/components/IndicatorParams.vue +570 -0
  35. package/src/components/IndicatorSelector.vue +1042 -0
  36. package/src/components/KLineChart.vue +1570 -0
  37. package/src/components/KLineTooltip.vue +200 -0
  38. package/src/components/LeftToolbar.vue +844 -0
  39. package/src/components/MarkerTooltip.vue +155 -0
  40. package/src/components/index.ts +7 -0
  41. package/src/composables/useFullscreenTeleportTarget.ts +18 -0
  42. package/src/debug/canvasProfiler.ts +296 -0
  43. package/src/index.ts +402 -0
  44. package/src/version.ts +3 -0
  45. package/LICENSE +0 -21
  46. package/dist/favicon.ico +0 -0
  47. package/dist/mock-stock-data.json +0 -1
  48. package/dist/schema-CzmPW09E.cjs +0 -1
  49. package/dist/schema-DBMGp6Af.js +0 -437
  50. package/dist/src/App.vue.d.ts +0 -4
  51. package/dist/src/api/data/baostock.d.ts +0 -90
  52. package/dist/src/api/data/baostock.integration.test.d.ts +0 -1
  53. package/dist/src/api/data/index.d.ts +0 -26
  54. package/dist/src/api/data/kLine.d.ts +0 -11
  55. package/dist/src/api/data/types.d.ts +0 -33
  56. package/dist/src/api/data/unified.d.ts +0 -37
  57. package/dist/src/components/DrawingStyleToolbar.vue.d.ts +0 -12
  58. package/dist/src/components/KLineChart.vue.d.ts +0 -100
  59. package/dist/src/components/KLineTooltip.vue.d.ts +0 -17
  60. package/dist/src/components/MarkerTooltip.vue.d.ts +0 -13
  61. package/dist/src/components/index.d.ts +0 -2
  62. package/dist/src/config/chartSettings.d.ts +0 -69
  63. package/dist/src/core/chart-store.d.ts +0 -74
  64. package/dist/src/core/chart.d.ts +0 -420
  65. package/dist/src/core/controller/interaction.d.ts +0 -167
  66. package/dist/src/core/controller/markerInteraction.d.ts +0 -28
  67. package/dist/src/core/controller/pinchTracker.d.ts +0 -18
  68. package/dist/src/core/controller/tooltipPosition.d.ts +0 -21
  69. package/dist/src/core/draw/pixelAlign.d.ts +0 -114
  70. package/dist/src/core/drawing/index.d.ts +0 -47
  71. package/dist/src/core/drawing/interaction.d.ts +0 -75
  72. package/dist/src/core/drawing/plugin.d.ts +0 -27
  73. package/dist/src/core/indicators/atrState.d.ts +0 -16
  74. package/dist/src/core/indicators/bollState.d.ts +0 -34
  75. package/dist/src/core/indicators/calculators.d.ts +0 -465
  76. package/dist/src/core/indicators/cciState.d.ts +0 -15
  77. package/dist/src/core/indicators/chaikinVolState.d.ts +0 -18
  78. package/dist/src/core/indicators/cmfState.d.ts +0 -16
  79. package/dist/src/core/indicators/demaState.d.ts +0 -16
  80. package/dist/src/core/indicators/donchianState.d.ts +0 -23
  81. package/dist/src/core/indicators/eneState.d.ts +0 -30
  82. package/dist/src/core/indicators/expmaState.d.ts +0 -30
  83. package/dist/src/core/indicators/fastkState.d.ts +0 -15
  84. package/dist/src/core/indicators/fibState.d.ts +0 -26
  85. package/dist/src/core/indicators/hmaState.d.ts +0 -16
  86. package/dist/src/core/indicators/hvState.d.ts +0 -18
  87. package/dist/src/core/indicators/ichimokuState.d.ts +0 -44
  88. package/dist/src/core/indicators/indicator.worker.d.ts +0 -5
  89. package/dist/src/core/indicators/indicatorRuntime.d.ts +0 -126
  90. package/dist/src/core/indicators/kamaState.d.ts +0 -20
  91. package/dist/src/core/indicators/keltnerState.d.ts +0 -27
  92. package/dist/src/core/indicators/kstState.d.ts +0 -21
  93. package/dist/src/core/indicators/maState.d.ts +0 -26
  94. package/dist/src/core/indicators/macdState.d.ts +0 -58
  95. package/dist/src/core/indicators/mfiState.d.ts +0 -16
  96. package/dist/src/core/indicators/momState.d.ts +0 -15
  97. package/dist/src/core/indicators/obvState.d.ts +0 -14
  98. package/dist/src/core/indicators/parkinsonState.d.ts +0 -18
  99. package/dist/src/core/indicators/pivotState.d.ts +0 -29
  100. package/dist/src/core/indicators/pvtState.d.ts +0 -14
  101. package/dist/src/core/indicators/rocState.d.ts +0 -16
  102. package/dist/src/core/indicators/rsiState.d.ts +0 -39
  103. package/dist/src/core/indicators/sarState.d.ts +0 -26
  104. package/dist/src/core/indicators/scheduler.d.ts +0 -237
  105. package/dist/src/core/indicators/soa.d.ts +0 -115
  106. package/dist/src/core/indicators/stateComposer.d.ts +0 -146
  107. package/dist/src/core/indicators/stochState.d.ts +0 -18
  108. package/dist/src/core/indicators/structureState.d.ts +0 -43
  109. package/dist/src/core/indicators/supertrendState.d.ts +0 -22
  110. package/dist/src/core/indicators/temaState.d.ts +0 -16
  111. package/dist/src/core/indicators/trixState.d.ts +0 -20
  112. package/dist/src/core/indicators/vmaState.d.ts +0 -16
  113. package/dist/src/core/indicators/volumeProfileState.d.ts +0 -34
  114. package/dist/src/core/indicators/vwapState.d.ts +0 -16
  115. package/dist/src/core/indicators/wmaState.d.ts +0 -16
  116. package/dist/src/core/indicators/wmsrState.d.ts +0 -15
  117. package/dist/src/core/indicators/workerProtocol.d.ts +0 -496
  118. package/dist/src/core/indicators/zonesState.d.ts +0 -26
  119. package/dist/src/core/layout/pane.d.ts +0 -103
  120. package/dist/src/core/marker/registry.d.ts +0 -174
  121. package/dist/src/core/paneRenderer.d.ts +0 -45
  122. package/dist/src/core/renderers/Indicator/atr.d.ts +0 -17
  123. package/dist/src/core/renderers/Indicator/boll.d.ts +0 -2
  124. package/dist/src/core/renderers/Indicator/cci.d.ts +0 -21
  125. package/dist/src/core/renderers/Indicator/chaikinVol.d.ts +0 -4
  126. package/dist/src/core/renderers/Indicator/cmf.d.ts +0 -4
  127. package/dist/src/core/renderers/Indicator/dema.d.ts +0 -5
  128. package/dist/src/core/renderers/Indicator/donchian.d.ts +0 -5
  129. package/dist/src/core/renderers/Indicator/ene.d.ts +0 -10
  130. package/dist/src/core/renderers/Indicator/expma.d.ts +0 -2
  131. package/dist/src/core/renderers/Indicator/fastk.d.ts +0 -21
  132. package/dist/src/core/renderers/Indicator/fib.d.ts +0 -4
  133. package/dist/src/core/renderers/Indicator/hma.d.ts +0 -5
  134. package/dist/src/core/renderers/Indicator/hv.d.ts +0 -4
  135. package/dist/src/core/renderers/Indicator/ichimoku.d.ts +0 -5
  136. package/dist/src/core/renderers/Indicator/index.d.ts +0 -59
  137. package/dist/src/core/renderers/Indicator/indicatorData.d.ts +0 -13
  138. package/dist/src/core/renderers/Indicator/kama.d.ts +0 -5
  139. package/dist/src/core/renderers/Indicator/keltner.d.ts +0 -5
  140. package/dist/src/core/renderers/Indicator/kst.d.ts +0 -21
  141. package/dist/src/core/renderers/Indicator/ma.d.ts +0 -3
  142. package/dist/src/core/renderers/Indicator/macd.d.ts +0 -49
  143. package/dist/src/core/renderers/Indicator/macdLegend.d.ts +0 -12
  144. package/dist/src/core/renderers/Indicator/mainIndicatorLegend.d.ts +0 -10
  145. package/dist/src/core/renderers/Indicator/mfi.d.ts +0 -4
  146. package/dist/src/core/renderers/Indicator/mom.d.ts +0 -21
  147. package/dist/src/core/renderers/Indicator/obv.d.ts +0 -4
  148. package/dist/src/core/renderers/Indicator/parkinson.d.ts +0 -4
  149. package/dist/src/core/renderers/Indicator/pivot.d.ts +0 -4
  150. package/dist/src/core/renderers/Indicator/pvt.d.ts +0 -4
  151. package/dist/src/core/renderers/Indicator/roc.d.ts +0 -5
  152. package/dist/src/core/renderers/Indicator/rsi.d.ts +0 -32
  153. package/dist/src/core/renderers/Indicator/sar.d.ts +0 -5
  154. package/dist/src/core/renderers/Indicator/scale/atr_scale.d.ts +0 -11
  155. package/dist/src/core/renderers/Indicator/scale/cci_scale.d.ts +0 -11
  156. package/dist/src/core/renderers/Indicator/scale/fastk_scale.d.ts +0 -11
  157. package/dist/src/core/renderers/Indicator/scale/indicator_scale.d.ts +0 -35
  158. package/dist/src/core/renderers/Indicator/scale/kst_scale.d.ts +0 -11
  159. package/dist/src/core/renderers/Indicator/scale/macd_scale.d.ts +0 -14
  160. package/dist/src/core/renderers/Indicator/scale/mom_scale.d.ts +0 -11
  161. package/dist/src/core/renderers/Indicator/scale/rsi_scale.d.ts +0 -11
  162. package/dist/src/core/renderers/Indicator/scale/stoch_scale.d.ts +0 -11
  163. package/dist/src/core/renderers/Indicator/scale/volume_scale.d.ts +0 -14
  164. package/dist/src/core/renderers/Indicator/scale/wmsr_scale.d.ts +0 -11
  165. package/dist/src/core/renderers/Indicator/stoch.d.ts +0 -21
  166. package/dist/src/core/renderers/Indicator/structure.d.ts +0 -4
  167. package/dist/src/core/renderers/Indicator/subPaneConfig.d.ts +0 -9
  168. package/dist/src/core/renderers/Indicator/supertrend.d.ts +0 -5
  169. package/dist/src/core/renderers/Indicator/tema.d.ts +0 -5
  170. package/dist/src/core/renderers/Indicator/trix.d.ts +0 -5
  171. package/dist/src/core/renderers/Indicator/vma.d.ts +0 -4
  172. package/dist/src/core/renderers/Indicator/volumeProfile.d.ts +0 -4
  173. package/dist/src/core/renderers/Indicator/vwap.d.ts +0 -4
  174. package/dist/src/core/renderers/Indicator/wma.d.ts +0 -5
  175. package/dist/src/core/renderers/Indicator/wmsr.d.ts +0 -21
  176. package/dist/src/core/renderers/Indicator/zones.d.ts +0 -4
  177. package/dist/src/core/renderers/candle.d.ts +0 -20
  178. package/dist/src/core/renderers/crosshair.d.ts +0 -17
  179. package/dist/src/core/renderers/customMarkers.d.ts +0 -6
  180. package/dist/src/core/renderers/extremaMarkers.d.ts +0 -5
  181. package/dist/src/core/renderers/gridLines.d.ts +0 -7
  182. package/dist/src/core/renderers/lastPrice.d.ts +0 -9
  183. package/dist/src/core/renderers/paneTitle.d.ts +0 -40
  184. package/dist/src/core/renderers/subVolume.d.ts +0 -13
  185. package/dist/src/core/renderers/timeAxis.d.ts +0 -14
  186. package/dist/src/core/renderers/webgl/candleSurface.d.ts +0 -80
  187. package/dist/src/core/renderers/webgl/sharedWebGLSurface.d.ts +0 -33
  188. package/dist/src/core/renderers/yAxis.d.ts +0 -14
  189. package/dist/src/core/scale/logFormula.d.ts +0 -66
  190. package/dist/src/core/scale/price.d.ts +0 -11
  191. package/dist/src/core/scale/priceScale.d.ts +0 -87
  192. package/dist/src/core/subPaneManager.d.ts +0 -22
  193. package/dist/src/core/theme/colors.d.ts +0 -243
  194. package/dist/src/core/theme/fonts.d.ts +0 -12
  195. package/dist/src/core/utils/klineConfig.d.ts +0 -28
  196. package/dist/src/core/utils/tickCount.d.ts +0 -8
  197. package/dist/src/core/utils/tickPosition.d.ts +0 -24
  198. package/dist/src/core/utils/zoom.d.ts +0 -30
  199. package/dist/src/core/viewport/viewport.d.ts +0 -31
  200. package/dist/src/index.d.ts +0 -8
  201. package/dist/src/main.d.ts +0 -0
  202. package/dist/src/plugin/ConfigManager.d.ts +0 -31
  203. package/dist/src/plugin/EventBus.d.ts +0 -34
  204. package/dist/src/plugin/HookSystem.d.ts +0 -28
  205. package/dist/src/plugin/PluginHost.d.ts +0 -54
  206. package/dist/src/plugin/PluginRegistry.d.ts +0 -40
  207. package/dist/src/plugin/StateStore.d.ts +0 -37
  208. package/dist/src/plugin/index.d.ts +0 -11
  209. package/dist/src/plugin/rendererPluginManager.d.ts +0 -77
  210. package/dist/src/plugin/stateKeys.d.ts +0 -6
  211. package/dist/src/plugin/types.d.ts +0 -439
  212. package/dist/src/semantic/controller.d.ts +0 -35
  213. package/dist/src/semantic/drawShape.d.ts +0 -14
  214. package/dist/src/semantic/index.d.ts +0 -8
  215. package/dist/src/semantic/types.d.ts +0 -298
  216. package/dist/src/semantic/validator.d.ts +0 -43
  217. package/dist/src/test-setup.d.ts +0 -6
  218. package/dist/src/types/kLine.d.ts +0 -3
  219. package/dist/src/types/price.d.ts +0 -31
  220. package/dist/src/types/volumePrice.d.ts +0 -26
  221. package/dist/src/utils/cache.d.ts +0 -33
  222. package/dist/src/utils/dateFormat.d.ts +0 -83
  223. package/dist/src/utils/http.d.ts +0 -14
  224. package/dist/src/utils/kLineDraw/MA.d.ts +0 -12
  225. package/dist/src/utils/kLineDraw/axis.d.ts +0 -150
  226. package/dist/src/utils/kLineDraw/grid.d.ts +0 -30
  227. package/dist/src/utils/kLineDraw/kLine.d.ts +0 -15
  228. package/dist/src/utils/kline/format.d.ts +0 -14
  229. package/dist/src/utils/kline/viewport.d.ts +0 -10
  230. package/dist/src/utils/logger.d.ts +0 -5
  231. package/dist/src/utils/mock/genRandomPriceData.d.ts +0 -3
  232. package/dist/src/utils/priceToY.d.ts +0 -7
  233. package/dist/src/utils/volumePrice.d.ts +0 -54
@@ -0,0 +1,844 @@
1
+ <template>
2
+ <nav class="left-toolbar" aria-label="?????">
3
+ <div class="left-toolbar__group">
4
+ <div v-for="tool in primaryTools" :key="tool.id" class="tool-item">
5
+ <button
6
+ type="button"
7
+ class="left-toolbar__button"
8
+ :class="{ active: isActive(tool) }"
9
+ :title="tool.title"
10
+ :aria-label="tool.title"
11
+ @click="selectTool(tool)"
12
+ @pointerdown.stop
13
+ @pointermove.stop
14
+ @pointerup.stop
15
+ >
16
+ <component :is="tool.icon" class="tool-icon" aria-hidden="true" />
17
+ <span
18
+ v-if="tool.children && tool.children.length"
19
+ class="corner-indicator"
20
+ :class="{ open: openGroupId === tool.id }"
21
+ @click.stop="toggleExpand(tool.id)"
22
+ aria-label="?????"
23
+ ></span>
24
+ </button>
25
+
26
+ <Transition name="dropdown">
27
+ <div
28
+ v-if="openGroupId === tool.id && tool.children && tool.children.length"
29
+ class="tool-dropdown"
30
+ @pointerdown.stop
31
+ @pointermove.stop
32
+ @pointerup.stop
33
+ >
34
+ <button
35
+ v-for="child in tool.children"
36
+ :key="child.id"
37
+ type="button"
38
+ class="left-toolbar__button"
39
+ :class="{ active: selectedToolId === child.id }"
40
+ :title="child.title"
41
+ :aria-label="child.title"
42
+ @click="selectChild(child)"
43
+ >
44
+ <component :is="child.icon" class="tool-icon" aria-hidden="true" />
45
+ </button>
46
+ </div>
47
+ </Transition>
48
+ </div>
49
+ </div>
50
+
51
+ <span class="left-toolbar__divider"></span>
52
+
53
+ <div class="left-toolbar__group">
54
+ <button
55
+ type="button"
56
+ class="left-toolbar__button"
57
+ title="??"
58
+ aria-label="??"
59
+ @click="$emit('zoomIn')"
60
+ @pointerdown.stop
61
+ @pointermove.stop
62
+ @pointerup.stop
63
+ >
64
+ <IconTablerZoomIn class="tool-icon" aria-hidden="true" />
65
+ </button>
66
+ <button
67
+ type="button"
68
+ class="left-toolbar__button"
69
+ title="??"
70
+ aria-label="??"
71
+ @click="$emit('zoomOut')"
72
+ @pointerdown.stop
73
+ @pointermove.stop
74
+ @pointerup.stop
75
+ >
76
+ <IconTablerZoomOut class="tool-icon" aria-hidden="true" />
77
+ </button>
78
+ </div>
79
+
80
+ <span class="left-toolbar__divider"></span>
81
+
82
+ <div class="left-toolbar__group">
83
+ <button
84
+ type="button"
85
+ class="left-toolbar__button"
86
+ :title="isFullscreen ? '????' : '????'"
87
+ :aria-label="isFullscreen ? '????' : '????'"
88
+ @click="$emit('toggleFullscreen')"
89
+ @pointerdown.stop
90
+ @pointermove.stop
91
+ @pointerup.stop
92
+ >
93
+ <IconTablerMinimize v-if="isFullscreen" class="tool-icon" aria-hidden="true" />
94
+ <IconTablerMaximize v-else class="tool-icon" aria-hidden="true" />
95
+ </button>
96
+ </div>
97
+
98
+ <span class="left-toolbar__divider"></span>
99
+
100
+ <div class="left-toolbar__group">
101
+ <button
102
+ type="button"
103
+ class="left-toolbar__button"
104
+ title="??"
105
+ aria-label="??"
106
+ @click="openSettings"
107
+ @pointerdown.stop
108
+ @pointermove.stop
109
+ @pointerup.stop
110
+ >
111
+ <IconTablerSettings class="tool-icon" aria-hidden="true" />
112
+ </button>
113
+ </div>
114
+ </nav>
115
+
116
+ <!-- ???? -->
117
+ <Teleport :to="teleportTarget">
118
+ <Transition name="overlay">
119
+ <div v-if="showSettings" class="settings-overlay" @click="closeSettings">
120
+ <Transition name="modal">
121
+ <div class="settings-modal" @click.stop>
122
+ <!-- ?? -->
123
+ <div class="settings-header">
124
+ <div class="header-left">
125
+ <span class="settings-title">????</span>
126
+ <span class="settings-subtitle">?????</span>
127
+ </div>
128
+ <div class="header-right">
129
+ <button class="settings-close" @click="closeSettings">
130
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
131
+ <path d="M18 6L6 18M6 6l12 12" />
132
+ </svg>
133
+ </button>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- ?? -->
138
+ <div class="settings-body">
139
+ <!-- ???? -->
140
+ <template v-if="mainSettings.length > 0">
141
+ <div class="settings-section-divider">
142
+ <span class="settings-section-label">????</span>
143
+ </div>
144
+ <template v-for="item in mainSettings" :key="item.key">
145
+ <div class="settings-item">
146
+ <label class="settings-label">
147
+ <span>{{ item.label }}</span>
148
+ <template v-if="item.type === 'boolean'">
149
+ <input
150
+ type="checkbox"
151
+ class="settings-checkbox"
152
+ v-model="settings[item.key]"
153
+ />
154
+ </template>
155
+ <template v-else-if="item.type === 'select' && item.options">
156
+ <select class="settings-select" v-model="settings[item.key]">
157
+ <option v-for="opt in item.options" :key="opt.value" :value="opt.value">
158
+ {{ opt.label }}
159
+ </option>
160
+ </select>
161
+ </template>
162
+ </label>
163
+ </div>
164
+ </template>
165
+ </template>
166
+
167
+ <!-- ????? -->
168
+ <template v-if="experimentalSettings.length > 0">
169
+ <div class="settings-section-divider">
170
+ <span class="settings-section-label">??? / ????</span>
171
+ </div>
172
+ <template v-for="item in experimentalSettings" :key="item.key">
173
+ <div class="settings-item experimental">
174
+ <label class="settings-label">
175
+ <span>{{ item.label }}</span>
176
+ <template v-if="item.type === 'boolean'">
177
+ <input
178
+ type="checkbox"
179
+ class="settings-checkbox"
180
+ v-model="settings[item.key]"
181
+ />
182
+ </template>
183
+ <template v-else-if="item.type === 'select' && item.options">
184
+ <select class="settings-select" v-model="settings[item.key]">
185
+ <option v-for="opt in item.options" :key="opt.value" :value="opt.value">
186
+ {{ opt.label }}
187
+ </option>
188
+ </select>
189
+ </template>
190
+ </label>
191
+ </div>
192
+ </template>
193
+ </template>
194
+ </div>
195
+
196
+ <!-- ?? -->
197
+ <div class="settings-footer">
198
+ <button class="settings-btn reset" @click="resetSettings">
199
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
200
+ <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
201
+ <path d="M3 3v5h5" />
202
+ </svg>
203
+ ??
204
+ </button>
205
+ <div class="footer-right">
206
+ <button class="settings-btn cancel" @click="closeSettings">??</button>
207
+ <button class="settings-btn confirm" @click="confirmSettings">
208
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
209
+ <path d="M20 6L9 17l-5-5" />
210
+ </svg>
211
+ ??
212
+ </button>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </Transition>
217
+ </div>
218
+ </Transition>
219
+ </Teleport>
220
+ </template>
221
+
222
+ <script setup lang="ts">
223
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
224
+ import IconTablerPointer from '~icons/tabler/pointer'
225
+ import IconTablerChartLine from '~icons/tabler/chart-line'
226
+ import IconTablerArrowUpRight from '~icons/tabler/arrow-up-right'
227
+ import IconTablerArrowRight from '~icons/tabler/arrow-right'
228
+ import IconTablerMinus from '~icons/tabler/minus'
229
+ import IconTablerSeparator from '~icons/tabler/separator'
230
+ import IconTablerCrosshair from '~icons/tabler/crosshair'
231
+ import IconTablerInfoCircle from '~icons/tabler/info-circle'
232
+ import IconTablerZoomIn from '~icons/tabler/zoom-in'
233
+ import IconTablerZoomOut from '~icons/tabler/zoom-out'
234
+ import IconTablerMaximize from '~icons/tabler/maximize'
235
+ import IconTablerMinimize from '~icons/tabler/minimize'
236
+ import IconTablerSettings from '~icons/tabler/settings'
237
+ import IconTablerShape from '~icons/tabler/shape'
238
+ import IconTablerChartDots3 from '~icons/tabler/chart-dots-3'
239
+ import IconTablerCaretUpDown from '~icons/tabler/caret-up-down'
240
+ import IconTablerBrackets from '~icons/tabler/brackets'
241
+ import {
242
+ DEFAULT_SETTINGS,
243
+ SETTINGS_STORAGE_KEY,
244
+ type SettingItem,
245
+ } from '@363045841yyt/klinechart-core/config'
246
+ import { useFullscreenTeleportTarget } from '../composables/useFullscreenTeleportTarget'
247
+ import { setCanvasProfilerEnabled } from '../debug/canvasProfiler'
248
+
249
+ export interface ToolDef {
250
+ id: string
251
+ title: string
252
+ icon: unknown
253
+ children?: ToolDef[]
254
+ }
255
+
256
+ const primaryTools: ToolDef[] = [
257
+ { id: 'cursor', title: '??', icon: IconTablerPointer },
258
+ {
259
+ id: 'lines',
260
+ title: '??',
261
+ icon: IconTablerChartLine,
262
+ children: [
263
+ { id: 'trend-line', title: '??', icon: IconTablerChartLine },
264
+ { id: 'ray', title: '??', icon: IconTablerArrowUpRight },
265
+ { id: 'h-line', title: '???', icon: IconTablerMinus },
266
+ { id: 'h-ray', title: '????', icon: IconTablerArrowRight },
267
+ { id: 'v-line', title: '???', icon: IconTablerSeparator },
268
+ { id: 'crosshair-line', title: '???', icon: IconTablerCrosshair },
269
+ { id: 'info-line', title: '???', icon: IconTablerInfoCircle },
270
+ ],
271
+ },
272
+ {
273
+ id: 'channels',
274
+ title: '??',
275
+ icon: IconTablerShape,
276
+ children: [
277
+ { id: 'parallel-channel', title: '????', icon: IconTablerShape },
278
+ { id: 'regression-channel', title: '????', icon: IconTablerChartDots3 },
279
+ { id: 'flat-line', title: '????', icon: IconTablerCaretUpDown },
280
+ { id: 'disjoint-channel', title: '?????', icon: IconTablerBrackets },
281
+ ],
282
+ },
283
+ ]
284
+
285
+ defineProps<{
286
+ isFullscreen?: boolean
287
+ }>()
288
+
289
+ const emit = defineEmits<{
290
+ (e: 'selectTool', toolId: string): void
291
+ (e: 'toggleFullscreen'): void
292
+ (e: 'zoomIn'): void
293
+ (e: 'zoomOut'): void
294
+ (e: 'settingsChange', settings: Record<string, boolean | string>): void
295
+ }>()
296
+
297
+ const selectedToolId = ref('cursor')
298
+ const openGroupId = ref<string | null>(null)
299
+ const showSettings = ref(false)
300
+
301
+ const teleportTarget = useFullscreenTeleportTarget()
302
+
303
+ const mainSettings = computed(
304
+ () => DEFAULT_SETTINGS.filter((s) => s.group === 'main') as unknown as SettingItem[],
305
+ )
306
+ const experimentalSettings = computed(
307
+ () => DEFAULT_SETTINGS.filter((s) => s.group === 'experimental') as unknown as SettingItem[],
308
+ )
309
+
310
+ function loadSettings(): Record<string, boolean | string> {
311
+ try {
312
+ const saved = localStorage.getItem(SETTINGS_STORAGE_KEY)
313
+ if (saved) {
314
+ const parsed = JSON.parse(saved)
315
+ const result: Record<string, boolean | string> = {}
316
+ DEFAULT_SETTINGS.forEach((item) => {
317
+ result[item.key] = parsed[item.key] ?? item.default
318
+ })
319
+ return result
320
+ }
321
+ } catch {}
322
+ const defaults: Record<string, boolean | string> = {}
323
+ DEFAULT_SETTINGS.forEach((item) => {
324
+ defaults[item.key] = item.default
325
+ })
326
+ return defaults
327
+ }
328
+
329
+ function saveSettings(settings: Record<string, boolean | string>) {
330
+ try {
331
+ localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings))
332
+ } catch {}
333
+ }
334
+
335
+ const appliedSettings = ref<Record<string, boolean | string>>(loadSettings())
336
+ const settings = ref<Record<string, boolean | string>>({ ...appliedSettings.value })
337
+
338
+ function isActive(tool: ToolDef): boolean {
339
+ if (selectedToolId.value === tool.id) return true
340
+ if (tool.children) {
341
+ return tool.children.some((c) => c.id === selectedToolId.value)
342
+ }
343
+ return false
344
+ }
345
+
346
+ function selectTool(tool: ToolDef) {
347
+ if (tool.children?.length) {
348
+ const hasActiveChild = tool.children.some((c) => c.id === selectedToolId.value)
349
+ if (!hasActiveChild) {
350
+ const first = tool.children[0]!
351
+ selectedToolId.value = first.id
352
+ emit('selectTool', first.id)
353
+ }
354
+ toggleExpand(tool.id)
355
+ return
356
+ }
357
+ selectedToolId.value = tool.id
358
+ emit('selectTool', tool.id)
359
+ openGroupId.value = null
360
+ }
361
+
362
+ function selectChild(child: ToolDef) {
363
+ selectedToolId.value = child.id
364
+ emit('selectTool', child.id)
365
+ openGroupId.value = null
366
+ }
367
+
368
+ function toggleExpand(groupId: string) {
369
+ openGroupId.value = openGroupId.value === groupId ? null : groupId
370
+ }
371
+
372
+ function openSettings() {
373
+ settings.value = { ...appliedSettings.value }
374
+ showSettings.value = true
375
+ }
376
+
377
+ function closeSettings() {
378
+ showSettings.value = false
379
+ }
380
+
381
+ function resetSettings() {
382
+ const defaults: Record<string, boolean | string> = {}
383
+ DEFAULT_SETTINGS.forEach((item) => {
384
+ defaults[item.key] = item.default
385
+ })
386
+ settings.value = defaults
387
+ }
388
+
389
+ function confirmSettings() {
390
+ appliedSettings.value = { ...settings.value }
391
+ saveSettings(appliedSettings.value)
392
+ setCanvasProfilerEnabled(!!appliedSettings.value['enableCanvasProfiler'])
393
+ emit('settingsChange', { ...appliedSettings.value })
394
+ closeSettings()
395
+ }
396
+
397
+ function getCurrentSettings(): Record<string, boolean | string> {
398
+ return { ...appliedSettings.value }
399
+ }
400
+
401
+ defineExpose({
402
+ getSettings: getCurrentSettings,
403
+ })
404
+
405
+ function handleClickOutside(e: MouseEvent) {
406
+ const target = e.target as HTMLElement
407
+ if (!target.closest('.tool-item')) {
408
+ openGroupId.value = null
409
+ }
410
+ }
411
+
412
+ onMounted(() => {
413
+ document.addEventListener('click', handleClickOutside, true)
414
+ emit('settingsChange', { ...appliedSettings.value })
415
+ setCanvasProfilerEnabled(!!appliedSettings.value['enableCanvasProfiler'])
416
+ })
417
+
418
+ onUnmounted(() => {
419
+ document.removeEventListener('click', handleClickOutside, true)
420
+ })
421
+ </script>
422
+
423
+ <style scoped>
424
+ .left-toolbar {
425
+ flex: 0 0 40px;
426
+ display: flex;
427
+ flex-direction: column;
428
+ align-items: center;
429
+ gap: 6px;
430
+ padding: 8px 5px;
431
+ border: 1px solid #e5e7eb;
432
+ border-radius: 6px;
433
+ background: #fafbfc;
434
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
435
+ box-sizing: border-box;
436
+ user-select: none;
437
+ }
438
+
439
+ .left-toolbar__group {
440
+ display: flex;
441
+ flex-direction: column;
442
+ gap: 4px;
443
+ }
444
+
445
+ .left-toolbar__divider {
446
+ width: 18px;
447
+ height: 1px;
448
+ background: #e5e7eb;
449
+ }
450
+
451
+ /* --- ???? --- */
452
+ .left-toolbar__button {
453
+ position: relative;
454
+ width: 28px;
455
+ height: 28px;
456
+ padding: 0;
457
+ border: 1px solid transparent;
458
+ border-radius: 4px;
459
+ background: transparent;
460
+ color: #6b7280;
461
+ cursor: pointer;
462
+ display: inline-flex;
463
+ align-items: center;
464
+ justify-content: center;
465
+ transition:
466
+ border-color 0.15s ease,
467
+ background 0.15s ease,
468
+ color 0.15s ease;
469
+ }
470
+
471
+ .left-toolbar__button:hover {
472
+ border-color: #d1d5db;
473
+ background: #f3f4f6;
474
+ color: #374151;
475
+ }
476
+
477
+ .left-toolbar__button.active {
478
+ border-color: #9ca3af;
479
+ background: #e5e7eb;
480
+ color: #1f2937;
481
+ }
482
+
483
+ .left-toolbar__button:focus-visible {
484
+ outline: none;
485
+ border-color: #6b7280;
486
+ }
487
+
488
+ .tool-icon {
489
+ width: 16px;
490
+ height: 16px;
491
+ }
492
+
493
+ /* --- ?????TradingView ??? --- */
494
+ .corner-indicator {
495
+ position: absolute;
496
+ right: 0;
497
+ bottom: 0;
498
+ width: 8px;
499
+ height: 8px;
500
+ cursor: pointer;
501
+ overflow: hidden;
502
+ }
503
+
504
+ .corner-indicator::after {
505
+ content: '';
506
+ position: absolute;
507
+ right: 0;
508
+ bottom: 0;
509
+ width: 0;
510
+ height: 0;
511
+ border-left: 5px solid transparent;
512
+ border-bottom: 5px solid currentColor;
513
+ opacity: 0.45;
514
+ transition: opacity 0.15s ease;
515
+ }
516
+
517
+ .left-toolbar__button:hover .corner-indicator::after {
518
+ opacity: 0.7;
519
+ }
520
+
521
+ .left-toolbar__button.active .corner-indicator::after {
522
+ opacity: 0.7;
523
+ }
524
+
525
+ .corner-indicator.open::after {
526
+ opacity: 0.8;
527
+ }
528
+
529
+ /* --- ????????????????????????????? --- */
530
+ .tool-dropdown {
531
+ position: absolute;
532
+ left: calc(100% + 13px);
533
+ top: 50%;
534
+ transform: translateY(-50%);
535
+ display: flex;
536
+ flex-direction: row;
537
+ align-items: center;
538
+ gap: 4px;
539
+ padding: 0 5px;
540
+ height: 40px;
541
+ background: rgba(250, 251, 252, 0.82);
542
+ backdrop-filter: blur(8px);
543
+ -webkit-backdrop-filter: blur(8px);
544
+ border: 1px solid #e5e7eb;
545
+ border-radius: 6px;
546
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
547
+ box-sizing: border-box;
548
+ z-index: 100;
549
+ }
550
+
551
+ /* --- ????? --- */
552
+ .tool-item {
553
+ position: relative;
554
+ }
555
+
556
+ /* --- ???? --- */
557
+ .dropdown-enter-active,
558
+ .dropdown-leave-active {
559
+ transition:
560
+ opacity 0.15s ease,
561
+ transform 0.15s ease;
562
+ }
563
+
564
+ .dropdown-enter-from,
565
+ .dropdown-leave-to {
566
+ opacity: 0;
567
+ transform: translateY(-50%) translateX(-6px);
568
+ }
569
+
570
+ /* --- ??? --- */
571
+ @media (max-width: 768px), (max-height: 640px) {
572
+ .left-toolbar {
573
+ flex-basis: 36px;
574
+ padding: 6px 4px;
575
+ gap: 5px;
576
+ border-radius: 5px;
577
+ }
578
+
579
+ .left-toolbar__group {
580
+ gap: 3px;
581
+ }
582
+
583
+ .left-toolbar__button {
584
+ width: 26px;
585
+ height: 26px;
586
+ border-radius: 3px;
587
+ }
588
+
589
+ .left-toolbar__divider {
590
+ width: 16px;
591
+ }
592
+
593
+ .corner-indicator {
594
+ width: 7px;
595
+ height: 7px;
596
+ }
597
+
598
+ .corner-indicator::after {
599
+ border-left-width: 4px;
600
+ border-bottom-width: 4px;
601
+ }
602
+
603
+ .tool-dropdown {
604
+ height: 36px;
605
+ }
606
+ }
607
+
608
+ /* ??? ????????? IndicatorParams.vue???? */
609
+ .settings-overlay {
610
+ position: fixed;
611
+ inset: 0;
612
+ background: rgba(0, 0, 0, 0.3);
613
+ backdrop-filter: blur(4px);
614
+ display: flex;
615
+ align-items: center;
616
+ justify-content: center;
617
+ z-index: 1000;
618
+ }
619
+
620
+ .settings-modal {
621
+ background: #ffffff;
622
+ border: 1px solid #e0e0e0;
623
+ border-radius: 12px;
624
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.15);
625
+ min-width: 340px;
626
+ max-width: 420px;
627
+ width: 90vw;
628
+ overflow: hidden;
629
+ }
630
+
631
+ .settings-header {
632
+ display: flex;
633
+ justify-content: space-between;
634
+ align-items: center;
635
+ padding: 16px 20px;
636
+ background: #f8f8f8;
637
+ border-bottom: 1px solid #e8e8e8;
638
+ }
639
+
640
+ .header-left {
641
+ display: flex;
642
+ align-items: baseline;
643
+ gap: 8px;
644
+ }
645
+
646
+ .header-right {
647
+ display: flex;
648
+ align-items: center;
649
+ gap: 8px;
650
+ }
651
+
652
+ .settings-title {
653
+ font-size: 14px;
654
+ font-weight: 600;
655
+ color: #1a1a1a;
656
+ letter-spacing: 0.2px;
657
+ }
658
+
659
+ .settings-subtitle {
660
+ font-size: 11px;
661
+ color: #999;
662
+ }
663
+
664
+ .settings-close {
665
+ background: #fff;
666
+ border: 1px solid #e0e0e0;
667
+ border-radius: 6px;
668
+ width: 28px;
669
+ height: 28px;
670
+ display: flex;
671
+ align-items: center;
672
+ justify-content: center;
673
+ cursor: pointer;
674
+ color: #888;
675
+ transition:
676
+ background 0.15s,
677
+ color 0.15s,
678
+ border-color 0.15s;
679
+ padding: 0;
680
+ }
681
+
682
+ .settings-close:hover {
683
+ background: #f0f0f0;
684
+ color: #333;
685
+ border-color: #ccc;
686
+ }
687
+
688
+ .settings-close svg {
689
+ width: 14px;
690
+ height: 14px;
691
+ }
692
+
693
+ .settings-body {
694
+ padding: 16px 20px;
695
+ display: flex;
696
+ flex-direction: column;
697
+ gap: 10px;
698
+ }
699
+
700
+ .settings-item {
701
+ padding: 8px 12px;
702
+ border-radius: 8px;
703
+ background: #f8f8f8;
704
+ border: 1px solid #e8e8e8;
705
+ }
706
+
707
+ .settings-label {
708
+ display: flex;
709
+ align-items: center;
710
+ justify-content: space-between;
711
+ font-size: 13px;
712
+ color: #333;
713
+ cursor: pointer;
714
+ }
715
+
716
+ .settings-checkbox {
717
+ width: 16px;
718
+ height: 16px;
719
+ cursor: pointer;
720
+ accent-color: #1a1a1a;
721
+ }
722
+
723
+ .settings-select {
724
+ padding: 4px 8px;
725
+ border: 1px solid #d0d0d0;
726
+ border-radius: 6px;
727
+ background: #fff;
728
+ color: #333;
729
+ font-size: 12px;
730
+ cursor: pointer;
731
+ outline: none;
732
+ min-width: 140px;
733
+ }
734
+
735
+ .settings-select:hover {
736
+ border-color: #9ca3af;
737
+ }
738
+
739
+ .settings-select:focus {
740
+ border-color: #6b7280;
741
+ box-shadow: 0 0 0 2px rgba(107, 114, 128, 0.15);
742
+ }
743
+
744
+ .settings-section-divider {
745
+ display: flex;
746
+ align-items: center;
747
+ gap: 8px;
748
+ margin-top: 4px;
749
+ }
750
+
751
+ .settings-section-divider::before,
752
+ .settings-section-divider::after {
753
+ content: '';
754
+ flex: 1;
755
+ border-top: 1px solid #e0e0e0;
756
+ }
757
+
758
+ .settings-section-label {
759
+ font-size: 11px;
760
+ color: #999;
761
+ white-space: nowrap;
762
+ }
763
+
764
+ .settings-item.experimental {
765
+ border-color: #f0e0d0;
766
+ background: #fdf8f3;
767
+ }
768
+
769
+ .settings-footer {
770
+ display: flex;
771
+ align-items: center;
772
+ justify-content: space-between;
773
+ padding: 12px 20px;
774
+ background: #f8f8f8;
775
+ border-top: 1px solid #e8e8e8;
776
+ }
777
+
778
+ .footer-right {
779
+ display: flex;
780
+ gap: 8px;
781
+ }
782
+
783
+ .settings-btn {
784
+ display: flex;
785
+ align-items: center;
786
+ gap: 5px;
787
+ padding: 6px 14px;
788
+ border-radius: 7px;
789
+ font-size: 13px;
790
+ font-weight: 500;
791
+ cursor: pointer;
792
+ border: 1px solid transparent;
793
+ transition: all 0.15s;
794
+ line-height: 1.4;
795
+ }
796
+
797
+ .settings-btn svg {
798
+ width: 12px;
799
+ height: 12px;
800
+ flex-shrink: 0;
801
+ }
802
+
803
+ .settings-btn.reset {
804
+ background: transparent;
805
+ border-color: #d0d0d0;
806
+ color: #666;
807
+ }
808
+
809
+ .settings-btn.reset:hover {
810
+ border-color: #c0392b;
811
+ color: #e74c3c;
812
+ background: rgba(231, 76, 60, 0.08);
813
+ }
814
+
815
+ .settings-btn.cancel {
816
+ background: transparent;
817
+ border-color: #d0d0d0;
818
+ color: #666;
819
+ }
820
+
821
+ .settings-btn.cancel:hover {
822
+ background: #f0f0f0;
823
+ color: #333;
824
+ border-color: #bbb;
825
+ }
826
+
827
+ .settings-btn.confirm {
828
+ background: #1a1a1a;
829
+ border-color: #1a1a1a;
830
+ color: #fff;
831
+ }
832
+
833
+ .settings-btn.confirm:hover {
834
+ background: #333;
835
+ border-color: #333;
836
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
837
+ transform: translateY(-1px);
838
+ }
839
+
840
+ .settings-btn.confirm:active {
841
+ transform: translateY(0);
842
+ box-shadow: none;
843
+ }
844
+ </style>