@devexperts/dxcharts-lite 1.0.1 → 2.0.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 (379) hide show
  1. package/README.md +4 -4
  2. package/dist/chart/animation/canvas-animation.d.ts +1 -1
  3. package/dist/chart/animation/canvas-animation.js +135 -2
  4. package/dist/chart/animation/types/animation.d.ts +1 -1
  5. package/dist/chart/animation/types/animation.js +44 -2
  6. package/dist/chart/animation/types/color-alpha-animation.d.ts +2 -2
  7. package/dist/chart/animation/types/color-alpha-animation.js +61 -2
  8. package/dist/chart/animation/types/color-transition-animation.d.ts +2 -2
  9. package/dist/chart/animation/types/color-transition-animation.js +87 -2
  10. package/dist/chart/animation/types/viewport-movement-animation.d.ts +1 -1
  11. package/dist/chart/animation/types/viewport-movement-animation.js +64 -2
  12. package/dist/chart/animation/viewport-model-animation.d.ts +1 -1
  13. package/dist/chart/animation/viewport-model-animation.js +21 -2
  14. package/dist/chart/bootstrap.d.ts +52 -49
  15. package/dist/chart/bootstrap.js +450 -2
  16. package/dist/chart/canvas/canvas-bounds-container.d.ts +1 -6
  17. package/dist/chart/canvas/canvas-bounds-container.js +816 -2
  18. package/dist/chart/canvas/canvas-chart-html.d.ts +1 -1
  19. package/dist/chart/canvas/canvas-chart-html.js +17 -19
  20. package/dist/chart/canvas/chart-elements.d.ts +2 -5
  21. package/dist/chart/canvas/chart-elements.js +23 -2
  22. package/dist/chart/canvas/cursor.handler.d.ts +1 -1
  23. package/dist/chart/canvas/cursor.handler.js +123 -2
  24. package/dist/chart/canvas/layout-creator.d.ts +1 -1
  25. package/dist/chart/canvas/layout-creator.js +35 -2
  26. package/dist/chart/canvas/y-axis-bounds.container.d.ts +3 -3
  27. package/dist/chart/canvas/y-axis-bounds.container.js +68 -2
  28. package/dist/chart/chart-container.d.ts +1 -1
  29. package/dist/chart/chart-container.js +2 -2
  30. package/dist/chart/chart.config.d.ts +5 -6
  31. package/dist/chart/chart.config.js +646 -2
  32. package/dist/chart/chart.d.ts +62 -0
  33. package/dist/chart/chart.js +106 -0
  34. package/dist/chart/components/chart/basic-scale.d.ts +3 -3
  35. package/dist/chart/components/chart/basic-scale.js +32 -2
  36. package/dist/chart/components/chart/candle-transformer.functions.d.ts +1 -1
  37. package/dist/chart/components/chart/candle-transformer.functions.js +16 -2
  38. package/dist/chart/components/chart/candle-width-calculator.functions.d.ts +1 -1
  39. package/dist/chart/components/chart/candle-width-calculator.functions.js +3 -2
  40. package/dist/chart/components/chart/candle.functions.d.ts +1 -1
  41. package/dist/chart/components/chart/candle.functions.js +45 -2
  42. package/dist/chart/components/chart/chart-area-pan.handler.d.ts +4 -4
  43. package/dist/chart/components/chart/chart-area-pan.handler.js +198 -2
  44. package/dist/chart/components/chart/chart-base.model.d.ts +1 -1
  45. package/dist/chart/components/chart/chart-base.model.js +67 -2
  46. package/dist/chart/components/chart/chart.component.d.ts +8 -4
  47. package/dist/chart/components/chart/chart.component.js +409 -2
  48. package/dist/chart/components/chart/chart.model.d.ts +5 -12
  49. package/dist/chart/components/chart/chart.model.js +955 -2
  50. package/dist/chart/components/chart/data-series.high-low-provider.d.ts +1 -1
  51. package/dist/chart/components/chart/data-series.high-low-provider.js +35 -2
  52. package/dist/chart/components/chart/fake-candles.d.ts +1 -1
  53. package/dist/chart/components/chart/fake-candles.js +98 -2
  54. package/dist/chart/components/chart/price.formatter.d.ts +1 -1
  55. package/dist/chart/components/chart/price.formatter.js +36 -2
  56. package/dist/chart/components/chart/secondary-chart-colors-pool.d.ts +1 -1
  57. package/dist/chart/components/chart/secondary-chart-colors-pool.js +69 -2
  58. package/dist/chart/components/cross_tool/cross-tool.component.d.ts +1 -1
  59. package/dist/chart/components/cross_tool/cross-tool.component.js +86 -2
  60. package/dist/chart/components/cross_tool/cross-tool.drawer.d.ts +1 -1
  61. package/dist/chart/components/cross_tool/cross-tool.drawer.js +33 -2
  62. package/dist/chart/components/cross_tool/cross-tool.model.d.ts +1 -1
  63. package/dist/chart/components/cross_tool/cross-tool.model.js +108 -2
  64. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.d.ts +1 -1
  65. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +138 -2
  66. package/dist/chart/components/cross_tool/types/none.drawer.d.ts +1 -1
  67. package/dist/chart/components/cross_tool/types/none.drawer.js +4 -2
  68. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-x.component.d.ts +1 -1
  69. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-x.component.js +29 -2
  70. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-y.component.d.ts +1 -1
  71. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-y.component.js +25 -2
  72. package/dist/chart/components/dran-n-drop_helper/drag-n-drop.component.d.ts +1 -1
  73. package/dist/chart/components/dran-n-drop_helper/drag-n-drop.component.js +54 -2
  74. package/dist/chart/components/dynamic-objects/dynamic-objects.component.d.ts +13 -0
  75. package/dist/chart/components/dynamic-objects/dynamic-objects.component.js +20 -0
  76. package/dist/chart/components/dynamic-objects/dynamic-objects.drawer.d.ts +18 -0
  77. package/dist/chart/components/dynamic-objects/dynamic-objects.drawer.js +23 -0
  78. package/dist/chart/components/dynamic-objects/dynamic-objects.model.d.ts +63 -0
  79. package/dist/chart/components/dynamic-objects/dynamic-objects.model.js +136 -0
  80. package/dist/chart/components/events/events-hit-test.drawer.d.ts +1 -1
  81. package/dist/chart/components/events/events-hit-test.drawer.js +64 -2
  82. package/dist/chart/components/events/events.component.d.ts +1 -1
  83. package/dist/chart/components/events/events.component.js +62 -2
  84. package/dist/chart/components/events/events.drawer.d.ts +1 -1
  85. package/dist/chart/components/events/events.drawer.js +196 -2
  86. package/dist/chart/components/events/events.model.d.ts +1 -1
  87. package/dist/chart/components/events/events.model.js +70 -2
  88. package/dist/chart/components/grid/grid.component.d.ts +3 -3
  89. package/dist/chart/components/grid/grid.component.js +32 -2
  90. package/dist/chart/components/grid/grid.drawer.d.ts +5 -4
  91. package/dist/chart/components/grid/grid.drawer.js +107 -2
  92. package/dist/chart/components/high_low/high-low.component.d.ts +1 -1
  93. package/dist/chart/components/high_low/high-low.component.js +13 -2
  94. package/dist/chart/components/high_low/high-low.drawer.d.ts +1 -1
  95. package/dist/chart/components/high_low/high-low.drawer.js +127 -2
  96. package/dist/chart/components/highlights/highlights.component.d.ts +1 -1
  97. package/dist/chart/components/highlights/highlights.component.js +47 -2
  98. package/dist/chart/components/highlights/highlights.drawer.d.ts +1 -1
  99. package/dist/chart/components/highlights/highlights.drawer.js +155 -2
  100. package/dist/chart/components/highlights/highlights.model.d.ts +1 -1
  101. package/dist/chart/components/highlights/highlights.model.js +76 -2
  102. package/dist/chart/components/labels_generator/numeric-axis-labels.generator.d.ts +2 -2
  103. package/dist/chart/components/labels_generator/numeric-axis-labels.generator.js +200 -2
  104. package/dist/chart/components/navigation_map/navigation-map-move.handler.d.ts +3 -3
  105. package/dist/chart/components/navigation_map/navigation-map-move.handler.js +109 -2
  106. package/dist/chart/components/navigation_map/navigation-map.component.d.ts +1 -1
  107. package/dist/chart/components/navigation_map/navigation-map.component.js +113 -2
  108. package/dist/chart/components/navigation_map/navigation-map.drawer.d.ts +1 -1
  109. package/dist/chart/components/navigation_map/navigation-map.drawer.js +245 -2
  110. package/dist/chart/components/navigation_map/navigation-map.model.d.ts +1 -1
  111. package/dist/chart/components/navigation_map/navigation-map.model.js +34 -3
  112. package/dist/chart/components/pan/chart-pan.component.d.ts +3 -3
  113. package/dist/chart/components/pan/chart-pan.component.js +52 -2
  114. package/dist/chart/components/pane/extent/y-extent-component.d.ts +13 -19
  115. package/dist/chart/components/pane/extent/y-extent-component.js +121 -2
  116. package/dist/chart/components/pane/pane-hit-test.controller.d.ts +1 -1
  117. package/dist/chart/components/pane/pane-hit-test.controller.js +56 -2
  118. package/dist/chart/components/pane/pane-manager.component.d.ts +11 -6
  119. package/dist/chart/components/pane/pane-manager.component.js +149 -2
  120. package/dist/chart/components/pane/pane.component.d.ts +18 -34
  121. package/dist/chart/components/pane/pane.component.js +279 -2
  122. package/dist/chart/components/resizer/bar-resizer.component.d.ts +1 -1
  123. package/dist/chart/components/resizer/bar-resizer.component.js +140 -2
  124. package/dist/chart/components/resizer/bar-resizer.drawer.d.ts +1 -1
  125. package/dist/chart/components/resizer/bar-resizer.drawer.js +47 -2
  126. package/dist/chart/components/snapshot/snapshot.component.d.ts +1 -1
  127. package/dist/chart/components/snapshot/snapshot.component.js +49 -2
  128. package/dist/chart/components/volumes/separate-volumes.component.d.ts +7 -11
  129. package/dist/chart/components/volumes/separate-volumes.component.js +64 -2
  130. package/dist/chart/components/volumes/volume-color-resolvers.functions.d.ts +1 -1
  131. package/dist/chart/components/volumes/volume-color-resolvers.functions.js +19 -2
  132. package/dist/chart/components/volumes/volumes.component.d.ts +9 -9
  133. package/dist/chart/components/volumes/volumes.component.js +95 -2
  134. package/dist/chart/components/volumes/volumes.drawer.d.ts +6 -13
  135. package/dist/chart/components/volumes/volumes.drawer.js +141 -2
  136. package/dist/chart/components/volumes/volumes.formatter.d.ts +1 -1
  137. package/dist/chart/components/volumes/volumes.formatter.js +32 -2
  138. package/dist/chart/components/volumes/volumes.model.d.ts +3 -3
  139. package/dist/chart/components/volumes/volumes.model.js +44 -2
  140. package/dist/chart/components/watermark/water-mark.component.d.ts +1 -1
  141. package/dist/chart/components/watermark/water-mark.component.js +104 -2
  142. package/dist/chart/components/watermark/water-mark.drawer.d.ts +1 -1
  143. package/dist/chart/components/watermark/water-mark.drawer.js +188 -2
  144. package/dist/chart/components/x_axis/numeric-x-axis-labels.generator.d.ts +1 -1
  145. package/dist/chart/components/x_axis/numeric-x-axis-labels.generator.js +28 -2
  146. package/dist/chart/components/x_axis/time/parser/time-formats-matchers.functions.d.ts +1 -1
  147. package/dist/chart/components/x_axis/time/parser/time-formats-matchers.functions.js +188 -2
  148. package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.d.ts +1 -1
  149. package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.js +77 -2
  150. package/dist/chart/components/x_axis/time/parser/time-formats-validators.functions.d.ts +1 -1
  151. package/dist/chart/components/x_axis/time/parser/time-formats-validators.functions.js +80 -2
  152. package/dist/chart/components/x_axis/time/parser/time-formats.model.d.ts +1 -1
  153. package/dist/chart/components/x_axis/time/parser/time-formats.model.js +15 -2
  154. package/dist/chart/components/x_axis/time/x-axis-weights.functions.d.ts +2 -2
  155. package/dist/chart/components/x_axis/time/x-axis-weights.functions.js +144 -2
  156. package/dist/chart/components/x_axis/time/x-axis-weights.generator.d.ts +1 -1
  157. package/dist/chart/components/x_axis/time/x-axis-weights.generator.js +74 -2
  158. package/dist/chart/components/x_axis/x-axis-draw.functions.d.ts +1 -1
  159. package/dist/chart/components/x_axis/x-axis-draw.functions.js +50 -2
  160. package/dist/chart/components/x_axis/x-axis-labels.drawer.d.ts +1 -1
  161. package/dist/chart/components/x_axis/x-axis-labels.drawer.js +71 -2
  162. package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +3 -3
  163. package/dist/chart/components/x_axis/x-axis-labels.generator.js +333 -2
  164. package/dist/chart/components/x_axis/x-axis-labels.model.d.ts +1 -1
  165. package/dist/chart/components/x_axis/x-axis-labels.model.js +36 -2
  166. package/dist/chart/components/x_axis/x-axis-scale.handler.d.ts +3 -3
  167. package/dist/chart/components/x_axis/x-axis-scale.handler.js +61 -2
  168. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.d.ts +1 -1
  169. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +83 -2
  170. package/dist/chart/components/x_axis/x-axis.component.d.ts +3 -3
  171. package/dist/chart/components/x_axis/x-axis.component.js +120 -2
  172. package/dist/chart/components/y_axis/label-color.functions.d.ts +1 -1
  173. package/dist/chart/components/y_axis/label-color.functions.js +54 -2
  174. package/dist/chart/components/y_axis/numeric-y-axis-labels.generator.d.ts +5 -5
  175. package/dist/chart/components/y_axis/numeric-y-axis-labels.generator.js +34 -2
  176. package/dist/chart/components/y_axis/price_labels/data-series-y-axis-labels.provider.d.ts +4 -4
  177. package/dist/chart/components/y_axis/price_labels/data-series-y-axis-labels.provider.js +68 -2
  178. package/dist/chart/components/y_axis/price_labels/labels-positions-calculator.d.ts +1 -1
  179. package/dist/chart/components/y_axis/price_labels/labels-positions-calculator.js +57 -2
  180. package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.d.ts +1 -1
  181. package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.js +96 -2
  182. package/dist/chart/components/y_axis/price_labels/price-label.drawer.d.ts +3 -3
  183. package/dist/chart/components/y_axis/price_labels/price-label.drawer.js +120 -2
  184. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.d.ts +10 -9
  185. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.js +202 -2
  186. package/dist/chart/components/y_axis/price_labels/y-axis-price-labels.drawer.d.ts +7 -8
  187. package/dist/chart/components/y_axis/price_labels/y-axis-price-labels.drawer.js +59 -2
  188. package/dist/chart/components/y_axis/y-axis-base-labels.model.d.ts +7 -5
  189. package/dist/chart/components/y_axis/y-axis-base-labels.model.js +48 -2
  190. package/dist/chart/components/y_axis/y-axis-labels.drawer.d.ts +5 -5
  191. package/dist/chart/components/y_axis/y-axis-labels.drawer.js +162 -2
  192. package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +3 -3
  193. package/dist/chart/components/y_axis/y-axis-scale.handler.js +73 -2
  194. package/dist/chart/components/y_axis/y-axis.component.d.ts +33 -42
  195. package/dist/chart/components/y_axis/y-axis.component.js +221 -2
  196. package/dist/chart/components/y_axis/y-axis.drawer.d.ts +10 -13
  197. package/dist/chart/components/y_axis/y-axis.drawer.js +97 -2
  198. package/dist/chart/components/y_axis/y-axis.model.d.ts +10 -18
  199. package/dist/chart/components/y_axis/y-axis.model.js +34 -2
  200. package/dist/chart/drawers/chart-background.drawer.d.ts +1 -1
  201. package/dist/chart/drawers/chart-background.drawer.js +70 -2
  202. package/dist/chart/drawers/chart-type-drawers/area.drawer.d.ts +1 -1
  203. package/dist/chart/drawers/chart-type-drawers/area.drawer.js +70 -2
  204. package/dist/chart/drawers/chart-type-drawers/bar.drawer.d.ts +1 -1
  205. package/dist/chart/drawers/chart-type-drawers/bar.drawer.js +58 -2
  206. package/dist/chart/drawers/chart-type-drawers/baseline.drawer.d.ts +1 -1
  207. package/dist/chart/drawers/chart-type-drawers/baseline.drawer.js +85 -2
  208. package/dist/chart/drawers/chart-type-drawers/candle.drawer.d.ts +1 -1
  209. package/dist/chart/drawers/chart-type-drawers/candle.drawer.js +163 -2
  210. package/dist/chart/drawers/chart-type-drawers/histogram.drawer.d.ts +1 -1
  211. package/dist/chart/drawers/chart-type-drawers/histogram.drawer.js +58 -2
  212. package/dist/chart/drawers/chart-type-drawers/line.drawer.d.ts +1 -1
  213. package/dist/chart/drawers/chart-type-drawers/line.drawer.js +39 -2
  214. package/dist/chart/drawers/chart-type-drawers/scatter-plot.drawer.d.ts +1 -1
  215. package/dist/chart/drawers/chart-type-drawers/scatter-plot.drawer.js +20 -2
  216. package/dist/chart/drawers/clear-canvas.drawer.d.ts +1 -1
  217. package/dist/chart/drawers/clear-canvas.drawer.js +15 -2
  218. package/dist/chart/drawers/composite.drawer.d.ts +1 -1
  219. package/dist/chart/drawers/composite.drawer.js +68 -2
  220. package/dist/chart/drawers/data-series-drawers/candle-series-wrapper.d.ts +1 -1
  221. package/dist/chart/drawers/data-series-drawers/candle-series-wrapper.js +51 -2
  222. package/dist/chart/drawers/data-series-drawers/color-candle.drawer.d.ts +1 -1
  223. package/dist/chart/drawers/data-series-drawers/color-candle.drawer.js +36 -2
  224. package/dist/chart/drawers/data-series-drawers/data-series-drawers.utils.d.ts +1 -1
  225. package/dist/chart/drawers/data-series-drawers/data-series-drawers.utils.js +17 -2
  226. package/dist/chart/drawers/data-series-drawers/difference-cloud.drawer.d.ts +1 -1
  227. package/dist/chart/drawers/data-series-drawers/difference-cloud.drawer.js +107 -2
  228. package/dist/chart/drawers/data-series-drawers/histogram.drawer.d.ts +1 -1
  229. package/dist/chart/drawers/data-series-drawers/histogram.drawer.js +24 -2
  230. package/dist/chart/drawers/data-series-drawers/linear.drawer.d.ts +1 -1
  231. package/dist/chart/drawers/data-series-drawers/linear.drawer.js +20 -2
  232. package/dist/chart/drawers/data-series-drawers/points.drawer.d.ts +1 -1
  233. package/dist/chart/drawers/data-series-drawers/points.drawer.js +20 -2
  234. package/dist/chart/drawers/data-series-drawers/rectangular-tool.drawer.d.ts +1 -1
  235. package/dist/chart/drawers/data-series-drawers/rectangular-tool.drawer.js +8 -2
  236. package/dist/chart/drawers/data-series-drawers/text.drawer.d.ts +1 -1
  237. package/dist/chart/drawers/data-series-drawers/text.drawer.js +26 -2
  238. package/dist/chart/drawers/data-series-drawers/trend-histogram.drawer.d.ts +1 -1
  239. package/dist/chart/drawers/data-series-drawers/trend-histogram.drawer.js +36 -2
  240. package/dist/chart/drawers/data-series-drawers/triangle.drawer.d.ts +1 -1
  241. package/dist/chart/drawers/data-series-drawers/triangle.drawer.js +23 -2
  242. package/dist/chart/drawers/data-series.drawer.d.ts +6 -8
  243. package/dist/chart/drawers/data-series.drawer.js +57 -2
  244. package/dist/chart/drawers/drawing-manager.d.ts +2 -2
  245. package/dist/chart/drawers/drawing-manager.js +178 -2
  246. package/dist/chart/drawers/ht-data-series.drawer.d.ts +1 -1
  247. package/dist/chart/drawers/ht-data-series.drawer.js +38 -2
  248. package/dist/chart/events/event-bus.d.ts +1 -1
  249. package/dist/chart/events/event-bus.js +74 -2
  250. package/dist/chart/events/events.d.ts +1 -1
  251. package/dist/chart/events/events.js +4 -2
  252. package/dist/chart/inputhandlers/candle-tap.handler.d.ts +1 -1
  253. package/dist/chart/inputhandlers/candle-tap.handler.js +47 -2
  254. package/dist/chart/inputhandlers/chart-resize.handler.d.ts +1 -1
  255. package/dist/chart/inputhandlers/chart-resize.handler.js +99 -2
  256. package/dist/chart/inputhandlers/cross-event-producer.component.d.ts +1 -1
  257. package/dist/chart/inputhandlers/cross-event-producer.component.js +68 -2
  258. package/dist/chart/inputhandlers/hover-producer.component.d.ts +3 -3
  259. package/dist/chart/inputhandlers/hover-producer.component.js +229 -2
  260. package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +3 -3
  261. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +81 -2
  262. package/dist/chart/inputlisteners/canvas-input-listener.component.d.ts +1 -1
  263. package/dist/chart/inputlisteners/canvas-input-listener.component.js +630 -2
  264. package/dist/chart/model/baseline.model.d.ts +1 -1
  265. package/dist/chart/model/baseline.model.js +89 -2
  266. package/dist/chart/model/bounds.model.d.ts +1 -1
  267. package/dist/chart/model/bounds.model.js +2 -2
  268. package/dist/chart/model/candle-hover.d.ts +1 -1
  269. package/dist/chart/model/candle-hover.js +71 -2
  270. package/dist/chart/model/candle-series-high-low.provider.d.ts +1 -1
  271. package/dist/chart/model/candle-series-high-low.provider.js +46 -2
  272. package/dist/chart/model/candle-series.model.d.ts +4 -4
  273. package/dist/chart/model/candle-series.model.js +246 -2
  274. package/dist/chart/model/candle.model.d.ts +1 -1
  275. package/dist/chart/model/candle.model.js +70 -2
  276. package/dist/chart/model/canvas.model.d.ts +1 -1
  277. package/dist/chart/model/canvas.model.js +229 -2
  278. package/dist/chart/model/chart-base-element.d.ts +1 -1
  279. package/dist/chart/model/chart-base-element.js +130 -2
  280. package/dist/chart/model/compare-series-hover.d.ts +1 -1
  281. package/dist/chart/model/compare-series-hover.js +26 -2
  282. package/dist/chart/model/data-series-view.d.ts +6 -6
  283. package/dist/chart/model/data-series-view.js +112 -2
  284. package/dist/chart/model/data-series.config.d.ts +1 -1
  285. package/dist/chart/model/data-series.config.js +15 -2
  286. package/dist/chart/model/data-series.model.d.ts +5 -5
  287. package/dist/chart/model/data-series.model.js +282 -2
  288. package/dist/chart/model/date-time.formatter.d.ts +1 -1
  289. package/dist/chart/model/date-time.formatter.js +152 -2
  290. package/dist/chart/model/hit-test-canvas.model.d.ts +2 -2
  291. package/dist/chart/model/hit-test-canvas.model.js +257 -2
  292. package/dist/chart/model/main-candle-series.model.d.ts +2 -2
  293. package/dist/chart/model/main-candle-series.model.js +30 -2
  294. package/dist/chart/model/scale.model.d.ts +3 -2
  295. package/dist/chart/model/scale.model.js +317 -2
  296. package/dist/chart/model/scaling/auto-scale.model.d.ts +1 -1
  297. package/dist/chart/model/scaling/auto-scale.model.js +98 -2
  298. package/dist/chart/model/scaling/constrait.functions.d.ts +1 -1
  299. package/dist/chart/model/scaling/constrait.functions.js +62 -2
  300. package/dist/chart/model/scaling/lock-ratio.model.d.ts +1 -1
  301. package/dist/chart/model/scaling/lock-ratio.model.js +18 -2
  302. package/dist/chart/model/scaling/move-chart.functions.d.ts +1 -1
  303. package/dist/chart/model/scaling/move-chart.functions.js +23 -2
  304. package/dist/chart/model/scaling/viewport.model.d.ts +3 -3
  305. package/dist/chart/model/scaling/viewport.model.js +280 -2
  306. package/dist/chart/model/scaling/x-zooming.functions.d.ts +1 -1
  307. package/dist/chart/model/scaling/x-zooming.functions.js +36 -2
  308. package/dist/chart/model/time-zone.model.d.ts +1 -1
  309. package/dist/chart/model/time-zone.model.js +110 -2
  310. package/dist/chart/model/visual-candle.d.ts +1 -1
  311. package/dist/chart/model/visual-candle.js +135 -2
  312. package/dist/chart/utils/__tests__/array.utils.test.d.ts +1 -1
  313. package/dist/chart/utils/__tests__/array.utils.test.js +136 -2
  314. package/dist/chart/utils/{perfomance/debounce.utils.js → __tests__/math.utils.test.d.ts} +2 -2
  315. package/dist/chart/utils/__tests__/math.utils.test.js +19 -0
  316. package/dist/chart/utils/__tests__/object.utils.test.d.ts +1 -1
  317. package/dist/chart/utils/__tests__/object.utils.test.js +12 -2
  318. package/dist/chart/utils/__tests__/priceIncrementsUtils.test.d.ts +1 -1
  319. package/dist/chart/utils/__tests__/priceIncrementsUtils.test.js +30 -2
  320. package/dist/chart/utils/array.utils.d.ts +2 -2
  321. package/dist/chart/utils/array.utils.js +270 -2
  322. package/dist/chart/utils/auto-period-detector.utils.d.ts +1 -1
  323. package/dist/chart/utils/auto-period-detector.utils.js +40 -2
  324. package/dist/chart/utils/candles-generator-ts.utils.d.ts +1 -1
  325. package/dist/chart/utils/candles-generator-ts.utils.js +21 -2
  326. package/dist/chart/utils/candles-generator.utils.d.ts +1 -1
  327. package/dist/chart/utils/candles-generator.utils.js +162 -2
  328. package/dist/chart/utils/candles.utils.d.ts +1 -1
  329. package/dist/chart/utils/candles.utils.js +43 -2
  330. package/dist/chart/utils/canvas/canvas-drawing-functions.utils.d.ts +1 -1
  331. package/dist/chart/utils/canvas/canvas-drawing-functions.utils.js +145 -2
  332. package/dist/chart/utils/canvas/canvas-font-measure-tool.utils.d.ts +1 -1
  333. package/dist/chart/utils/canvas/canvas-font-measure-tool.utils.js +52 -2
  334. package/dist/chart/utils/canvas/canvas-text-functions.utils.d.ts +1 -1
  335. package/dist/chart/utils/canvas/canvas-text-functions.utils.js +157 -2
  336. package/dist/chart/utils/color.utils.d.ts +1 -1
  337. package/dist/chart/utils/color.utils.js +32 -2
  338. package/dist/chart/utils/device/browser.utils.d.ts +1 -1
  339. package/dist/chart/utils/device/browser.utils.js +11 -2
  340. package/dist/chart/utils/device/device-detector.utils.d.ts +1 -1
  341. package/dist/chart/utils/device/device-detector.utils.js +25 -2
  342. package/dist/chart/utils/device/device-pixel-ratio.utils.d.ts +1 -1
  343. package/dist/chart/utils/device/device-pixel-ratio.utils.js +22 -2
  344. package/dist/chart/utils/device/touchpad.utils.d.ts +1 -1
  345. package/dist/chart/utils/device/touchpad.utils.js +92 -2
  346. package/dist/chart/utils/dom.utils.d.ts +1 -1
  347. package/dist/chart/utils/dom.utils.js +16 -2
  348. package/dist/chart/utils/function.utils.d.ts +1 -1
  349. package/dist/chart/utils/function.utils.js +17 -2
  350. package/dist/chart/utils/linkedList.utils.d.ts +28 -0
  351. package/dist/chart/utils/linkedList.utils.js +138 -0
  352. package/dist/chart/utils/math.utils.d.ts +1 -1
  353. package/dist/chart/utils/math.utils.js +116 -2
  354. package/dist/chart/utils/merge.utils.d.ts +1 -1
  355. package/dist/chart/utils/merge.utils.js +57 -2
  356. package/dist/chart/utils/object.utils.d.ts +1 -1
  357. package/dist/chart/utils/object.utils.js +44 -2
  358. package/dist/chart/utils/{perfomance → performance}/animation-frame-cache.utils.d.ts +1 -1
  359. package/dist/chart/utils/performance/animation-frame-cache.utils.js +77 -0
  360. package/dist/chart/utils/{perfomance → performance}/debounce.utils.d.ts +1 -1
  361. package/dist/chart/utils/performance/debounce.utils.js +12 -0
  362. package/dist/chart/utils/{perfomance → performance}/memoize.utils.d.ts +1 -1
  363. package/dist/chart/utils/performance/memoize.utils.js +74 -0
  364. package/dist/chart/utils/{perfomance → performance}/request-animation-frame-throttle.utils.d.ts +1 -1
  365. package/dist/chart/utils/performance/request-animation-frame-throttle.utils.js +43 -0
  366. package/dist/chart/utils/{perfomance → performance}/throttle.utils.d.ts +1 -1
  367. package/dist/chart/utils/performance/throttle.utils.js +26 -0
  368. package/dist/chart/utils/price-increments.utils.d.ts +2 -1
  369. package/dist/chart/utils/price-increments.utils.js +128 -2
  370. package/dist/chart/utils/uuid.utils.d.ts +1 -1
  371. package/dist/chart/utils/uuid.utils.js +5 -2
  372. package/dist/dxchart.min.js +10 -13
  373. package/dist/index.d.ts +4 -4
  374. package/dist/index.js +21 -2
  375. package/package.json +4 -4
  376. package/dist/chart/utils/perfomance/animation-frame-cache.utils.js +0 -6
  377. package/dist/chart/utils/perfomance/memoize.utils.js +0 -6
  378. package/dist/chart/utils/perfomance/request-animation-frame-throttle.utils.js +0 -6
  379. package/dist/chart/utils/perfomance/throttle.utils.js +0 -6
@@ -1,6 +1,959 @@
1
1
  /*
2
- * Copyright (C) 2002 - 2023 Devexperts LLC
2
+ * Copyright (C) 2019 - 2023 Devexperts Solutions IE Limited
3
3
  * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
4
  * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
5
  */
6
- import{Subject as p,merge as U}from"rxjs";import{distinctUntilChanged as A}from"rxjs/operators";import{ChartBaseElement as D}from"../../model/chart-base-element";import{CHART_UUID as C,CanvasElement as f,areBoundsChanged as W}from"../../canvas/canvas-bounds-container";import{getDefaultConfig as j}from"../../chart.config";import{MIN_SUPPORTED_CANVAS_SIZE as M}from"../../model/canvas.model";import{CandleSeriesModel as _}from"../../model/candle-series.model";import{copyCandle as O}from"../../model/candle.model";import{MainCandleSeriesModel as V}from"../../model/main-candle-series.model";import{candleEdgesConstrait as L}from"../../model/scaling/constrait.functions";import{pixelsToUnits as b}from"../../model/scaling/viewport.model";import{merge as X}from"../../utils/merge.utils";import{createBasicScaleViewportTransformer as Y,createTimeFrameViewportTransformer as R}from"./basic-scale";import{calculateCandleWidth as N}from"./candle-width-calculator.functions";import{deleteCandlesIndex as H,prepareCandle as S,reindexCandles as P}from"./candle.functions";import{ChartInstrument as k}from"./chart.component";import{fakeCandle as g}from"./fake-candles";import{SecondaryChartColorsPool as z}from"./secondary-chart-colors-pool";import{binarySearch as T,lastOf as w}from"../../utils/array.utils";import{searchCandleIndex as v}from"../../utils/candles.utils";import{floor as Z,round as K}from"../../utils/math.utils";export class ChartModel extends D{get mainCandleSeries(){return this.candleSeries[0]}get secondaryCandleSeries(){return this.candleSeries.filter(e=>e!==this.mainCandleSeries)}constructor(e,t,s,i,a,n,d,l,r,o){super(),this.chartBaseModel=e,this.paneManager=t,this.bus=s,this.canvasModel=i,this.config=a,this.scaleModel=n,this.formatterFactory=d,this.mainCanvasParent=l,this.canvasBoundsContainer=r,this.chartResizeHandler=o,this.prevChartWidth=0,this.prevYWidth=0,this.candleSeries=[],this.nextCandleTimeStampSubject=new p,this.axisTypeSetSubject=new p,this.chartTypeChanged=new p,this.mainInstrumentChangedSubject=new p,this.scaleInversedSubject=new p,this.offsetsChanged=new p,this.candlesTransformersByChartType={},this.lastCandleLabelsByChartType={},this.candleWidthByChartType={},this.lastTimeFrame=[0,0],this.FAKE_CANDLES_DEFAULT=100,this.toY=u=>this.mainCandleSeries.view.toY(u),this.chartTypeChanged.next(this.config.components.chart.type),this.secondaryChartColors=new z(this.config);const c=new V(this.chartBaseModel,this.paneManager.paneComponents[C].mainYExtentComponent,this.paneManager.hitTestController.getNewDataSeriesHitTestId(),this.bus,this.scaleModel,new k,this.candlesTransformersByChartType,this.candleWidthByChartType,Object.assign({},this.config.colors));c.config.type=this.config.components.chart.type,this.candleSeries.push(c),n.addXConstraint((u,m)=>L(m,this.mainCandleSeries.visualPoints,this.config.components.chart.minCandlesOffset,n.getBounds())),this.basicScaleViewportTransformer=Y(n),this.timeFrameViewportTransformer=R(n,this),this.pane=this.paneManager.paneComponents[C]}get candlesUpdatedSubject(){return this.chartBaseModel.dataUpdatedSubject}get candlesSetSubject(){return this.chartBaseModel.dataSetSubject}get candlesRemovedSubject(){return this.chartBaseModel.dataRemovedSubject}get candlesPrependSubject(){return this.chartBaseModel.dataPrependSubject}doActivate(){super.doActivate(),this.addRxSubscription(this.canvasBoundsContainer.observeBoundsChanged(f.PANE_UUID(C)).pipe(A(W)).subscribe(e=>{this.handleChartResize(e)}))}handleChartResize(e){if(e.width>M.width&&e.height>M.height){const t=this.getEffectiveChartWidth(),s=this.getEffectiveYAxisWidth();if(this.prevChartWidth===0){this.scaleModel.isViewportValid()?this.scaleModel.recalculateZoom():this.doBasicScale(),this.prevChartWidth=t,this.prevYWidth=s;return}if(s!==this.prevYWidth){if(this.config.scale.keepZoomXOnYAxisChange){const a=b(s-this.prevYWidth,this.scaleModel.zoomX);this.scaleModel.setXScale(this.scaleModel.xStart,this.scaleModel.xEnd-a)}else this.scaleModel.recalculateZoomX();this.prevYWidth=s,this.prevChartWidth=t;return}const i=b(t-this.prevChartWidth,this.scaleModel.zoomX);this.scaleModel.setXScale(this.scaleModel.xStart-i,this.scaleModel.xEnd),this.scaleModel.recalculateZoomY(),this.prevYWidth=s,this.prevChartWidth=t}}setMainCandleSeries(e,t){this.mainCandleSeries.instrument=t,this.setAllSeries({candles:e,instrument:t},this.getSecondarySeries().map(s=>{const i=s.dataPoints;return H(i),{candles:i,instrument:s.instrument}}))}setSecondaryCandleSeries(e,t=this.mainCandleSeries.instrument,s=!0){const i=y(e.map(S)),a=this.reindexCandlesBasedOnSeries(this.mainCandleSeries.dataPoints,i),n=this.secondarySeriesAdjustments(this.mainCandleSeries.dataPoints,a),l=this.secondaryCandleSeries.some(r=>r.instrument.symbol===t.symbol)?this.secondaryCandleSeries.find(r=>r.instrument.symbol===t.symbol):this.createSecondaryCandleSeriesModel(t);if(l)return l.dataPoints=n,s&&(this.scaleModel.doAutoScale(),l.recalculateVisualPoints(),this.candlesSetSubject.next(),this.bus.fireDraw([this.canvasModel.canvasId])),l}setAllSeries(e,t=[]){var s;this.mainCandleSeries.instrument=(s=e.instrument)!==null&&s!==void 0?s:this.mainCandleSeries.instrument,e.instrument&&this.mainInstrumentChangedSubject.next(e.instrument),this.rememberCurrentTimeframe();const i=y(e.candles.map(S));this.mainCandleSeries.clearData(),P(i),this.mainCandleSeries.dataPoints=i,this.secondaryCandleSeries.filter(a=>t.filter(n=>{var d;return((d=n.instrument)===null||d===void 0?void 0:d.symbol)===a.instrument.symbol}).length===0).forEach(a=>this.removeSecondaryCandleSeries(a)),t.map(a=>this.setSecondaryCandleSeries(a.candles,a.instrument,!1)),this.candleSeries.forEach(a=>{a.recalculateDataViewportIndexes(),a.recalculateVisualPoints()}),this.chartBaseModel.recalculatePeriod(),this.autoScaleOnCandles(),this.scaleModel.doAutoScale(),this.candlesSetSubject.next(),this.bus.fireDraw([this.canvasModel.canvasId])}autoScaleOnCandles(){this.scaleModel.state.autoScaleOnCandles&&(this.doBasicScale(),this.scaleModel.autoScale(!0))}doBasicScale(){this.basicScaleViewportTransformer(this.mainCandleSeries.visualPoints),this.bus.fireDraw()}doPreviousTimeFrameScale(e=null){this.timeFrameViewportTransformer(this.lastTimeFrame,e),this.scaleModel.state.autoScaleOnCandles&&this.scaleModel.doAutoScale(!0),this.bus.fireDraw()}rememberCurrentTimeframe(){this.mainCandleSeries.visualPoints.length!==0&&(this.lastTimeFrame=[this.candleFromX(this.scaleModel.toX(this.scaleModel.xStart),!0).timestamp,this.candleFromX(this.scaleModel.toX(this.scaleModel.xEnd),!0).timestamp])}updateAllSeries(e,t=[]){e=Object.assign({},e),e.instrument||(e.instrument=this.mainCandleSeries.instrument);const s=[e,...t];if(!this.candleSeries.every(l=>s.find(r=>{var o;return((o=r.instrument)===null||o===void 0?void 0:o.symbol)===l.instrument.symbol}))||t.length!==this.secondaryCandleSeries.length){console.error("All series update failed. Instruments for series are different.");return}const i=y(e.candles.map(S)),a=I(this.mainCandleSeries.dataPoints,i),n=a.candles;P(n),this.mainCandleSeries.dataPoints=n,t.map(l=>{var r,o,c,u;const m=y(l.candles.map(S)),x=I((u=(c=this.findSecondarySeriesBySymbol((o=(r=l.instrument)===null||r===void 0?void 0:r.symbol)!==null&&o!==void 0?o:""))===null||c===void 0?void 0:c.dataPoints)!==null&&u!==void 0?u:[],m).candles;return this.setSecondaryCandleSeries(x,l.instrument,!1)}),this.candleSeries.forEach(l=>{l.recalculateVisualPoints(),l.recalculateDataViewportIndexes()});const d=this.chartBaseModel.mainVisualPoints.slice(0,a.prepended).reduce((l,r)=>l+r.width,0);this.scaleModel.moveXStart(this.scaleModel.xStart+d),this.candlesPrependSubject.next({prependedCandlesWidth:d,preparedCandles:i}),this.chartBaseModel.recalculatePeriod(),this.candlesUpdatedSubject.next(),this.bus.fireDraw()}removeDataFrom(e){Object.values(this.paneManager.paneComponents).forEach(t=>{t.dataSeries.forEach(s=>{const i=T(s.dataPoints,e,n=>n.timestamp),a=i.exact?i.index:i.index+1;s.dataPoints=s.dataPoints.slice(0,a)})}),this.candlesRemovedSubject.next(),this.candlesUpdatedSubject.next(),this.canvasModel.fireDraw()}createSecondaryCandleSeriesModel(e){const t=Object.assign(Object.assign({},this.config.colors),this.secondaryChartColors.takeColorFromPool(e.symbol));return this.createCandleSeriesModel(e,t)}createCandleSeriesModel(e,t){const s=new _(this.paneManager.paneComponents[C].mainYExtentComponent,this.paneManager.hitTestController.getNewDataSeriesHitTestId(),this.bus,this.scaleModel,e,this.candlesTransformersByChartType,this.candleWidthByChartType,t);return s.config.type="line",this.candleSeries.push(s),s}removeSecondaryCandleSeries(e){return this.secondaryChartColors.addColorToPool(e.instrument.symbol),this.candleSeries=this.candleSeries.filter(t=>t!==e),e.deactivate(),this.paneManager.paneComponents[C].removeDataSeries(e),this.scaleModel.doAutoScale(),e.colors}secondarySeriesAdjustments(e,t){const s=[];return e.forEach(i=>{var a;const n=(a=i.idx)!==null&&a!==void 0?a:0,d=t[n];if(d)s.push(d);else{let l=B(t,n,-1);if(l||(l=B(t,n,1)),l){const r=O(l,n,!0);s.push(r)}}}),s}updateSecondaryCandleSeriesConfig(e,t,s){const i=X(e,j().colors);this.secondaryChartColors.updateColorConfig(t,i);const a=this.findSecondarySeriesBySymbol(t);a&&(a.config.type=s,a.updateCandleSeriesColors(i),this.bus.fireDraw([this.canvasModel.canvasId])),this.bus.fireDraw([this.canvasModel.canvasId])}setAutoScale(e){this.scaleModel.autoScale(e)}getEffectiveYAxisWidth(){return this.canvasBoundsContainer.getBounds(f.PANE_UUID_Y_AXIS(C)).width}getEffectiveChartWidth(){return this.canvasBoundsContainer.getBounds(f.PANE_UUID(C)).width}getEffectiveChartHeight(){return this.canvasBoundsContainer.getBounds(f.PANE_UUID(C)).height}setOffsets(e){this.scaleModel.updateOffsets(e);const t=this.getCandlesCountWithRightOffset(),s=this.mainCandleSeries.visualPoints;this.hasCandles()&&t>=s.length&&this.scaleModel.setXScale(this.scaleModel.xStart,this.candleFromIdx(t).startUnit),this.offsetsChanged.next(),this.bus.fireDraw()}getOffsets(){return this.scaleModel.getOffsets()}fromY(e){return this.scaleModel.fromY(e)}priceFromY(e,t){return(t!=null?t:this.mainCandleSeries).view.priceFromY(e)}fromX(e){return this.scaleModel.fromX(e)}toX(e){const t=this.candleFromIdx(e);return this.scaleModel.toX(t.centerUnit)}getBaseLine(){return this.mainCandleSeries.getBaseLine()}candleFromX(e,t=!1,s=this.mainCandleSeries){const i=this.scaleModel.fromX(e);return this.candleFromUnit(i,t,s)}candleFromUnit(e,t=!1,s=this.mainCandleSeries){var i,a;const n=T(s.visualPoints,e,c=>c.startUnit),d=s.visualPoints,l=this.getLastVisualCandle();d[n.index]!==void 0&&(e<0||l&&e>l.startUnit+l.width)&&(n.index+=K((e-d[n.index].centerUnit)/this.mainCandleSeries.meanCandleWidth));const r=n.index,o=Math.max(Math.min(d.length-1,r),0);return(r<0||r>=d.length)&&t?g(this.mainCandleSeries.dataPoints,r,this.chartBaseModel.period):(a=(i=d[o])===null||i===void 0?void 0:i.candle)!==null&&a!==void 0?a:g(this.mainCandleSeries.dataPoints,o,this.chartBaseModel.period)}candleFromTimestamp(e,t=!0){return this.chartBaseModel.dataFromTimestamp(e,t)}candleFromIdx(e){return this.chartBaseModel.dataFromIdx(e)}isReady(){return this.canvasModel.isReady()&&this.hasCandles()}registerCandlesTransformer(e,t){this.candlesTransformersByChartType[e]=t}registerCandlesWidthCalculator(e,t){this.candleWidthByChartType[e]=t}registerLastCandleLabelHandler(e,t){this.lastCandleLabelsByChartType[e]=t}hasCandles(){return this.mainCandleSeries.visualPoints.length!==0}getVisualCandle(e){var t,s,i;const a=e-((i=(s=(t=this.mainCandleSeries.visualPoints[0])===null||t===void 0?void 0:t.candle)===null||s===void 0?void 0:s.idx)!==null&&i!==void 0?i:0);return this.mainCandleSeries.visualPoints[a]}getFirstIdx(){return this.mainCandleSeries.dataIdxStart}getLastIdx(){return this.mainCandleSeries.dataIdxEnd}getFirstTimestamp(e=!0){return e?this.candleFromIdx(this.getFirstIdx()).candle.timestamp:this.candleFromUnit(this.scaleModel.xStart,!0).timestamp}getLastTimestamp(e=!0){return e?this.candleFromIdx(this.getLastIdx()).candle.timestamp:this.candleFromUnit(this.scaleModel.xEnd,!0).timestamp}setTimestampRange(e,t){const s=this.candleFromTimestamp(e).startUnit,i=this.candleFromTimestamp(t),a=i.startUnit+i.width;return this.scaleModel.setXScale(s,a)}getLastCandle(){const e=this.mainCandleSeries.dataPoints;return w(e)}getLastVisualCandle(){const e=this.mainCandleSeries.visualPoints;return w(e)}getMaxCandlesFitLength(){return Z(this.getEffectiveChartWidth()/this.config.components.chart.minWidth)}getSecondarySeries(){return this.secondaryCandleSeries}isSeriesInstrument(e,t){return e.instrument.symbol===t}findSeriesBySymbol(e){return this.candleSeries.filter(t=>this.isSeriesInstrument(t,e))}findSecondarySeriesBySymbol(e){return this.secondaryCandleSeries.find(t=>this.isSeriesInstrument(t,e))}reindexCandlesBasedOnSeries(e,t){return t.reduce((s,i)=>{const a=i.timestamp,n=v(a,!1,e,this.chartBaseModel.period);return n.index>=0&&n.index<e.length&&(i.idx=n.index,s[n.index]=i),s},[])}getPeriod(){return this.chartBaseModel.period}isCandleInViewport(e){return this.getFirstIdx()<=e&&e<=this.getLastIdx()}updateCandles(e,t=this.mainCandleSeries.instrument.symbol){const s=this.mainCandleSeries.instrument.symbol===t,i=this.findSeriesBySymbol(t);if(i.length===0){console.warn("updateCandles failed. Can't find series",t);return}i.forEach(a=>{const n=a.dataPoints;let d=!1,l=!1,r;e.forEach(o=>{var c;if(!o)return;const u=v(o.timestamp,!0,n,this.getPeriod()),m=Math.min(u.index,n.length);d=d||m===n.length,n[m]=o,o.idx=m,a.dataPoints=n,a.recalculateDataViewportIndexes(),l=l||this.isCandleInViewport(m);const x=m>=n.length-1,E=r&&o.timestamp<r.timestamp;if(x&&!E&&(r=o),d&&r&&s&&l){const F=(c=this.candleWidthByChartType[this.config.components.chart.type])!==null&&c!==void 0?c:N;this.scaleModel.moveXStart(this.scaleModel.xStart+F(r))}}),r&&a.updateCurrentPrice(r.close),l&&r&&e.length===1?this.bus.fireDraw([this.canvasModel.canvasId]):a.recalculateVisualPoints()}),this.scaleModel.doAutoScale(),this.candlesUpdatedSubject.next()}observeCandlesChanged(){return U(this.candlesSetSubject,this.candlesUpdatedSubject)}getCandles(){return this.mainCandleSeries.dataPoints}getCandlesWithFake(e=0,t){let s=this.getCandles().slice();const i=this.getCandlesCount(),a=t!=null?t:i+this.FAKE_CANDLES_DEFAULT;s=s.slice(Math.max(0,e),Math.min(i,a));const n=[],d=[];for(let r=i;r<a;r++)n.push(g(this.mainCandleSeries.dataPoints,r,this.getPeriod()));const l=Math.min(0,a);for(let r=e;r<l;r++)d.push(g(this.mainCandleSeries.dataPoints,r,this.getPeriod()));return[...d,...s,...n]}getCandlesCount(){return this.mainCandleSeries.dataPoints.length}getCandlesCountWithRightOffset(){return this.getCandlesCount()+this.getOffsets().right}clearData(){this.candleSeries.forEach(e=>e.clearData())}prependCandles(e,t){const s=e.slice(),i=[];return t.forEach(a=>{const d=v(a.timestamp,!1,e).index;d<0?i.push(a):e[d].timestamp===a.timestamp?s[d]=a:console.warn(`Couldn't update candle with timestamp ${a.timestamp}`)}),{prepended:i.length,candles:[...i,...s]}}addLastCandle(e,t=this.mainCandleSeries.instrument.symbol){this.updateCandles([e],t)}updateLastCandle(e,t=this.mainCandleSeries.instrument.symbol){this.updateCandles([e],t)}}const y=h=>h.slice().sort((e,t)=>e.timestamp===t.timestamp?0:e.timestamp>t.timestamp?1:-1),B=(h,e,t)=>{if(e>=h.length)return h[h.length-1];for(let s=e;s<h.length&&s>=0;s+=t){const i=h[s];if(i)return i}},I=(h,e)=>{const t=h.slice(),s=[],i=[];return e.forEach(a=>{const d=v(a.timestamp,!0,h).index;d<0?s.push(a):d>=h.length?i.push(a):h[d].timestamp===a.timestamp?t[d]=a:console.warn(`Couldn't update candle with timestamp ${a.timestamp}`)}),{prepended:s.length,appended:i.length,candles:[...s,...t,...i]}};
6
+ import { Subject, merge } from 'rxjs';
7
+ import { distinctUntilChanged } from 'rxjs/operators';
8
+ import { CHART_UUID, CanvasElement, areBoundsChanged, } from '../../canvas/canvas-bounds-container';
9
+ import { getDefaultConfig } from '../../chart.config';
10
+ import { CandleSeriesModel } from '../../model/candle-series.model';
11
+ import { copyCandle } from '../../model/candle.model';
12
+ import { MIN_SUPPORTED_CANVAS_SIZE } from '../../model/canvas.model';
13
+ import { ChartBaseElement } from '../../model/chart-base-element';
14
+ import { MainCandleSeriesModel } from '../../model/main-candle-series.model';
15
+ import { candleEdgesConstrait } from '../../model/scaling/constrait.functions';
16
+ import { pixelsToUnits } from '../../model/scaling/viewport.model';
17
+ import { binarySearch, lastOf } from '../../utils/array.utils';
18
+ import { searchCandleIndex } from '../../utils/candles.utils';
19
+ import { floor, round } from '../../utils/math.utils';
20
+ import { merge as mergeObj } from '../../utils/merge.utils';
21
+ import { createBasicScaleViewportTransformer, createTimeFrameViewportTransformer } from './basic-scale';
22
+ import { calculateCandleWidth } from './candle-width-calculator.functions';
23
+ import { deleteCandlesIndex, prepareCandle, reindexCandles } from './candle.functions';
24
+ import { ChartInstrument } from './chart.component';
25
+ import { fakeCandle } from './fake-candles';
26
+ import { SecondaryChartColorsPool } from './secondary-chart-colors-pool';
27
+ export class ChartModel extends ChartBaseElement {
28
+ get mainCandleSeries() {
29
+ return this.candleSeries[0];
30
+ }
31
+ get secondaryCandleSeries() {
32
+ return this.candleSeries.filter(s => s !== this.mainCandleSeries);
33
+ }
34
+ constructor(chartBaseModel, paneManager, bus, canvasModel, config, scale, formatterFactory, mainCanvasParent, canvasBoundsContainer, chartResizeHandler) {
35
+ super();
36
+ this.chartBaseModel = chartBaseModel;
37
+ this.paneManager = paneManager;
38
+ this.bus = bus;
39
+ this.canvasModel = canvasModel;
40
+ this.config = config;
41
+ this.scale = scale;
42
+ this.formatterFactory = formatterFactory;
43
+ this.mainCanvasParent = mainCanvasParent;
44
+ this.canvasBoundsContainer = canvasBoundsContainer;
45
+ this.chartResizeHandler = chartResizeHandler;
46
+ this.prevChartWidth = 0;
47
+ this.prevYWidth = 0;
48
+ this.candleSeries = [];
49
+ this.nextCandleTimeStampSubject = new Subject();
50
+ this.chartTypeChanged = new Subject();
51
+ this.mainInstrumentChangedSubject = new Subject();
52
+ this.scaleInversedSubject = new Subject();
53
+ this.offsetsChanged = new Subject();
54
+ this.candlesTransformersByChartType = {};
55
+ this.lastCandleLabelsByChartType = {};
56
+ this.candleWidthByChartType = {};
57
+ // TODO try to remove this state
58
+ this.lastTimeFrame = [0, 0];
59
+ this.FAKE_CANDLES_DEFAULT = 100;
60
+ this.toY = (value) => {
61
+ return this.mainCandleSeries.view.toY(value);
62
+ };
63
+ this.chartTypeChanged.next(this.config.components.chart.type);
64
+ this.secondaryChartColors = new SecondaryChartColorsPool(this.config);
65
+ const candleSeries = new MainCandleSeriesModel(this.chartBaseModel, this.paneManager.panes[CHART_UUID].mainExtent, this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, new ChartInstrument(), this.candlesTransformersByChartType, this.candleWidthByChartType, Object.assign({}, this.config.colors));
66
+ candleSeries.config.type = this.config.components.chart.type;
67
+ this.candleSeries.push(candleSeries);
68
+ scale.addXConstraint((_, state) => candleEdgesConstrait(state, this.mainCandleSeries.visualPoints, this.config.components.chart.minCandlesOffset, scale.getBounds()));
69
+ this.basicScaleViewportTransformer = createBasicScaleViewportTransformer(scale);
70
+ this.timeFrameViewportTransformer = createTimeFrameViewportTransformer(scale, this);
71
+ this.pane = this.paneManager.panes[CHART_UUID];
72
+ }
73
+ get candlesUpdatedSubject() {
74
+ return this.chartBaseModel.dataUpdatedSubject;
75
+ }
76
+ get candlesSetSubject() {
77
+ return this.chartBaseModel.dataSetSubject;
78
+ }
79
+ get candlesRemovedSubject() {
80
+ return this.chartBaseModel.dataRemovedSubject;
81
+ }
82
+ get candlesPrependSubject() {
83
+ return this.chartBaseModel.dataPrependSubject;
84
+ }
85
+ /**
86
+ * Method that activates the canvas bounds container and subscribes to its bounds changes and bar resizer changes.
87
+ * @protected
88
+ * @returns {void}
89
+ */
90
+ doActivate() {
91
+ super.doActivate();
92
+ this.addRxSubscription(this.canvasBoundsContainer
93
+ .observeBoundsChanged(CanvasElement.PANE_UUID(CHART_UUID))
94
+ .pipe(distinctUntilChanged(areBoundsChanged))
95
+ .subscribe(bounds => {
96
+ this.handleChartResize(bounds);
97
+ }));
98
+ }
99
+ /**
100
+ * This method keeps the same candle width on chart canvas resize, so chart candles aren't squeezed when canvas becomes smaller
101
+ * If chart width was changed after Yaxis width changed, scale will be adjusted to right/left, and visually nothing will be changed
102
+ * @private
103
+ * @param nextCB - Next chart bounds
104
+ */
105
+ handleChartResize(nextCB) {
106
+ if (nextCB.width > MIN_SUPPORTED_CANVAS_SIZE.width && nextCB.height > MIN_SUPPORTED_CANVAS_SIZE.height) {
107
+ const nextChartWidth = this.getEffectiveChartWidth();
108
+ const nextYAxisWidth = this.getEffectiveYAxisWidth();
109
+ if (this.prevChartWidth === 0) {
110
+ this.scale.isViewportValid() ? this.scale.recalculateZoom() : this.doBasicScale();
111
+ this.prevChartWidth = nextChartWidth;
112
+ this.prevYWidth = nextYAxisWidth;
113
+ return;
114
+ }
115
+ // YAxis width changed, so chart width will be changed too, but we need adjust scale to right/left
116
+ if (nextYAxisWidth !== this.prevYWidth) {
117
+ if (this.config.scale.keepZoomXOnYAxisChange) {
118
+ const unitDiff = pixelsToUnits(nextYAxisWidth - this.prevYWidth, this.scale.zoomX);
119
+ this.scale.setXScale(this.scale.xStart, this.scale.xEnd - unitDiff);
120
+ }
121
+ else {
122
+ this.scale.recalculateZoomX();
123
+ }
124
+ this.prevYWidth = nextYAxisWidth;
125
+ this.prevChartWidth = nextChartWidth;
126
+ return;
127
+ }
128
+ // YAxis has the same width, so keep the same candle width on chart resize
129
+ const unitDiff = pixelsToUnits(nextChartWidth - this.prevChartWidth, this.scale.zoomX);
130
+ this.scale.setXScale(this.scale.xStart - unitDiff, this.scale.xEnd);
131
+ // height also could be changed - we need correct zoomY
132
+ this.scale.recalculateZoomY();
133
+ this.prevYWidth = nextYAxisWidth;
134
+ this.prevChartWidth = nextChartWidth;
135
+ }
136
+ }
137
+ /**
138
+ * Sets the main candle series with the provided candles and instrument.
139
+ * @param {Array<Candle>} candles - The array of candles to set as the main candle series.
140
+ * @param {ChartInstrument} instrument - The instrument to set for the main candle series.
141
+ * @returns {void}
142
+ */
143
+ setMainCandleSeries(candles, instrument) {
144
+ this.mainCandleSeries.instrument = instrument;
145
+ this.setAllSeries({
146
+ candles,
147
+ instrument,
148
+ }, this.getSecondarySeries().map(series => {
149
+ const originalCandles = series.dataPoints;
150
+ // reset the idx of candles to calculate them again
151
+ deleteCandlesIndex(originalCandles);
152
+ return {
153
+ candles: originalCandles,
154
+ instrument: series.instrument,
155
+ };
156
+ }));
157
+ }
158
+ /**
159
+ * Sets a secondary candle series based on the provided candles array and instrument.
160
+ * @param {Array<Candle>} candles - An array of candles to set as the secondary candle series.
161
+ * @param {ChartInstrument} instrument - The instrument to set as the secondary candle series. Defaults to the main candle series instrument.
162
+ * @param {boolean} recalculateAndUpdate - A boolean indicating whether to recalculate and update the candle series. Defaults to true.
163
+ * @returns {CandleSeriesModel | undefined} - The newly created secondary candle series model or undefined if it could not be created.
164
+ */
165
+ setSecondaryCandleSeries(candles, instrument = this.mainCandleSeries.instrument, recalculateAndUpdate = true) {
166
+ const prepareCandleCandles = sortCandles(candles.map(prepareCandle));
167
+ // set correct indexes based on main candles timestamp
168
+ const reindexCandles = this.reindexCandlesBasedOnSeries(this.mainCandleSeries.dataPoints, prepareCandleCandles);
169
+ // ensure there are no gaps in new candles
170
+ const secondaryCandles = this.secondarySeriesAdjustments(this.mainCandleSeries.dataPoints, reindexCandles);
171
+ // create a new secondary series model if it doesn't already exist
172
+ const isSymbolExist = this.secondaryCandleSeries.some(candleSeries => candleSeries.instrument.symbol === instrument.symbol);
173
+ const candleSeriesModel = isSymbolExist
174
+ ? this.secondaryCandleSeries.find(candleSeries => candleSeries.instrument.symbol === instrument.symbol)
175
+ : this.createSecondaryCandleSeriesModel(instrument);
176
+ if (!candleSeriesModel) {
177
+ return;
178
+ }
179
+ candleSeriesModel.dataPoints = secondaryCandles;
180
+ if (recalculateAndUpdate) {
181
+ // calculate X and Y bounds
182
+ this.scale.doAutoScale();
183
+ // now the visual candles
184
+ candleSeriesModel.recalculateVisualPoints();
185
+ this.candlesSetSubject.next();
186
+ this.bus.fireDraw([this.canvasModel.canvasId]);
187
+ }
188
+ return candleSeriesModel;
189
+ }
190
+ /**
191
+ * Shouldn't be called outside chart-core, use ChartComponent#setAllSeries instead
192
+ * @param mainSeries
193
+ * @param secondarySeries
194
+ */
195
+ setAllSeries(mainSeries, secondarySeries = []) {
196
+ var _a;
197
+ this.mainCandleSeries.instrument = (_a = mainSeries.instrument) !== null && _a !== void 0 ? _a : this.mainCandleSeries.instrument;
198
+ if (mainSeries.instrument) {
199
+ this.mainInstrumentChangedSubject.next(mainSeries.instrument);
200
+ }
201
+ this.rememberCurrentTimeframe();
202
+ const prepareCandleCandles = sortCandles(mainSeries.candles.map(prepareCandle));
203
+ this.mainCandleSeries.clearData();
204
+ reindexCandles(prepareCandleCandles);
205
+ this.mainCandleSeries.dataPoints = prepareCandleCandles;
206
+ // deactivate deleted series
207
+ this.secondaryCandleSeries
208
+ .filter(series => {
209
+ return secondarySeries.filter(s => { var _a; return ((_a = s.instrument) === null || _a === void 0 ? void 0 : _a.symbol) === series.instrument.symbol; }).length === 0;
210
+ })
211
+ .forEach(series => this.removeSecondaryCandleSeries(series));
212
+ // re-create series
213
+ secondarySeries.map(series => this.setSecondaryCandleSeries(series.candles, series.instrument, false));
214
+ // do visual recalculations
215
+ this.candleSeries.forEach(series => {
216
+ series.recalculateDataViewportIndexes();
217
+ series.recalculateVisualPoints();
218
+ });
219
+ this.chartBaseModel.recalculatePeriod();
220
+ this.autoScaleOnCandles();
221
+ this.scale.doAutoScale();
222
+ this.candlesSetSubject.next();
223
+ this.bus.fireDraw([this.canvasModel.canvasId]);
224
+ }
225
+ /**
226
+ * This function checks if the autoScaleOnCandles state is true. If it is, it calls the doBasicScale() function and then calls the autoScale() function with a true parameter.
227
+ * @function
228
+ * @name autoScaleOnCandles
229
+ * @memberof ClassName
230
+ * @returns {void}
231
+ */
232
+ autoScaleOnCandles() {
233
+ if (this.scale.state.autoScaleOnCandles) {
234
+ this.doBasicScale();
235
+ this.scale.autoScale(true);
236
+ }
237
+ }
238
+ /**
239
+ * Applies the basic scale viewport transformer to the visual points of the main candle series and fires a draw event.
240
+ */
241
+ doBasicScale() {
242
+ this.basicScaleViewportTransformer(this.mainCandleSeries.visualPoints);
243
+ this.bus.fireDraw();
244
+ }
245
+ /**
246
+ * Changes the time frame scale to the previous one and redraws the chart.
247
+ * @param {boolean | null} zoomIn - If true, zooms in the chart, if false, zooms out the chart, if null, does not zoom.
248
+ * @returns {void}
249
+ */
250
+ doPreviousTimeFrameScale(zoomIn = null) {
251
+ this.timeFrameViewportTransformer(this.lastTimeFrame, zoomIn);
252
+ if (this.scale.state.autoScaleOnCandles) {
253
+ this.scale.doAutoScale(true);
254
+ }
255
+ this.bus.fireDraw();
256
+ }
257
+ /**
258
+ * Saves the current timeframe by getting the start and end timestamps of the visual candles in the main candle series.
259
+ * If there are no visual candles, the last timeframe is not updated.
260
+ */
261
+ rememberCurrentTimeframe() {
262
+ const visualCandles = this.mainCandleSeries.visualPoints;
263
+ if (visualCandles.length !== 0) {
264
+ this.lastTimeFrame = [
265
+ this.candleFromX(this.scale.toX(this.scale.xStart), true).timestamp,
266
+ this.candleFromX(this.scale.toX(this.scale.xEnd), true).timestamp,
267
+ ];
268
+ }
269
+ }
270
+ /**
271
+ * Shouldn't be called outside chart-core, use ChartComponent#updateAllSeries instead
272
+ * @param mainSeries
273
+ * @param secondarySeries
274
+ */
275
+ updateAllSeries(mainSeries, secondarySeries = []) {
276
+ mainSeries = Object.assign({}, mainSeries);
277
+ if (!mainSeries.instrument) {
278
+ mainSeries.instrument = this.mainCandleSeries.instrument;
279
+ }
280
+ const allSeries = [mainSeries, ...secondarySeries];
281
+ if (!this.candleSeries.every(s => allSeries.find(ss => { var _a; return ((_a = ss.instrument) === null || _a === void 0 ? void 0 : _a.symbol) === s.instrument.symbol; })) ||
282
+ secondarySeries.length !== this.secondaryCandleSeries.length) {
283
+ console.error('All series update failed. Instruments for series are different.');
284
+ return;
285
+ }
286
+ const preparedCandles = sortCandles(mainSeries.candles.map(prepareCandle));
287
+ const updateResult = updateCandles(this.mainCandleSeries.dataPoints, preparedCandles);
288
+ const updatedCandles = updateResult.candles;
289
+ reindexCandles(updatedCandles);
290
+ this.mainCandleSeries.dataPoints = updatedCandles;
291
+ // re-create series
292
+ secondarySeries.map(series => {
293
+ var _a, _b, _c, _d;
294
+ const preparedCandles = sortCandles(series.candles.map(prepareCandle));
295
+ const updatedCandles = updateCandles((_d = (_c = this.findSecondarySeriesBySymbol((_b = (_a = series.instrument) === null || _a === void 0 ? void 0 : _a.symbol) !== null && _b !== void 0 ? _b : '')) === null || _c === void 0 ? void 0 : _c.dataPoints) !== null && _d !== void 0 ? _d : [], preparedCandles).candles;
296
+ return this.setSecondaryCandleSeries(updatedCandles, series.instrument, false);
297
+ });
298
+ // do visual recalculations
299
+ this.candleSeries.forEach(series => {
300
+ series.recalculateVisualPoints();
301
+ series.recalculateDataViewportIndexes();
302
+ });
303
+ // caclulate offset width for prepanded candles
304
+ const prependedCandlesWidth = this.chartBaseModel.mainVisualPoints
305
+ .slice(0, updateResult.prepended)
306
+ .reduce((acc, cur) => acc + cur.width, 0);
307
+ this.scale.moveXStart(this.scale.xStart + prependedCandlesWidth);
308
+ this.candlesPrependSubject.next({
309
+ prependedCandlesWidth,
310
+ preparedCandles,
311
+ });
312
+ this.chartBaseModel.recalculatePeriod();
313
+ this.candlesUpdatedSubject.next();
314
+ this.bus.fireDraw();
315
+ }
316
+ /**
317
+ * Removes all data points from the main candle series that are newer than the given timestamp.
318
+ * Can be useful for data replay.
319
+ * @param startTimestamp
320
+ */
321
+ removeDataFrom(startTimestamp) {
322
+ Object.values(this.paneManager.panes).forEach(pane => {
323
+ pane.dataSeries.forEach(series => {
324
+ const searchResult = binarySearch(series.dataPoints, startTimestamp, p => p.timestamp);
325
+ const index = searchResult.exact ? searchResult.index : searchResult.index + 1;
326
+ series.dataPoints = series.dataPoints.slice(0, index);
327
+ });
328
+ });
329
+ this.candlesRemovedSubject.next();
330
+ this.candlesUpdatedSubject.next();
331
+ this.canvasModel.fireDraw();
332
+ }
333
+ /**
334
+ * Creates a secondary candle series model for a given instrument.
335
+ * @param {ChartInstrument} instrument - The instrument for which the secondary candle series model is created.
336
+ * @returns {CandleSeriesModel | undefined} - The created secondary candle series model or undefined if it cannot be created.
337
+ */
338
+ createSecondaryCandleSeriesModel(instrument) {
339
+ const candleSeriesConfig = Object.assign(Object.assign({}, this.config.colors), this.secondaryChartColors.takeColorFromPool(instrument.symbol));
340
+ return this.createCandleSeriesModel(instrument, candleSeriesConfig);
341
+ }
342
+ /**
343
+ * Creates a new CandleSeriesModel object and adds it to the chart.
344
+ * @param {ChartInstrument} instrument - The instrument to be displayed in the chart.
345
+ * @param {CandleSeriesColors} [colors] - Optional colors for the candle series.
346
+ * @returns {CandleSeriesModel} - The newly created CandleSeriesModel object.
347
+ */
348
+ createCandleSeriesModel(instrument, colors) {
349
+ const candleSeries = new CandleSeriesModel(this.paneManager.panes[CHART_UUID].mainExtent, this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, instrument, this.candlesTransformersByChartType, this.candleWidthByChartType, colors);
350
+ candleSeries.config.type = 'line';
351
+ this.candleSeries.push(candleSeries);
352
+ return candleSeries;
353
+ }
354
+ /**
355
+ * Removes a secondary candle series from the chart and returns its colors.
356
+ * @param {CandleSeriesModel} series - The candle series to be removed.
357
+ * @returns {CandleSeriesColors | undefined} - The colors of the removed series or undefined if the series was not found.
358
+ */
359
+ removeSecondaryCandleSeries(series) {
360
+ this.secondaryChartColors.addColorToPool(series.instrument.symbol);
361
+ this.candleSeries = this.candleSeries.filter(s => s !== series);
362
+ series.deactivate();
363
+ this.paneManager.panes[CHART_UUID].removeDataSeries(series);
364
+ this.scale.doAutoScale();
365
+ return series.colors;
366
+ }
367
+ /**
368
+ * Adjusts secondary series to present them nicely with main series:
369
+ * - fill gaps in secondarySeries with fake candles OHLC of same price (=close price)
370
+ * - do not add any candles which are not in main series
371
+ * @param mainSeries - main series
372
+ * @param secondarySeries - secondarySeries to adjust
373
+ */
374
+ secondarySeriesAdjustments(mainSeries, secondarySeries) {
375
+ const result = [];
376
+ mainSeries.forEach(mainCandle => {
377
+ var _a;
378
+ const idx = (_a = mainCandle.idx) !== null && _a !== void 0 ? _a : 0;
379
+ const compareCandle = secondarySeries[idx];
380
+ if (!compareCandle) {
381
+ // take first candle to left or right
382
+ // check left direction first
383
+ let candle = findFirstNotEmptyCandle(secondarySeries, idx, -1);
384
+ if (!candle) {
385
+ candle = findFirstNotEmptyCandle(secondarySeries, idx, 1);
386
+ }
387
+ if (candle) {
388
+ // copy the candle and simplify it's OHLC
389
+ const fakeCandle = copyCandle(candle, idx, true);
390
+ result.push(fakeCandle);
391
+ }
392
+ }
393
+ else {
394
+ result.push(compareCandle);
395
+ }
396
+ });
397
+ return result;
398
+ }
399
+ /**
400
+ * Updates the configuration of the secondary candle series with the provided colors and instrument symbol.
401
+ * @param {PartialCandleSeriesColors} config - The partial configuration object containing the colors to update.
402
+ * @param {string} instrumentSymbol - The symbol of the instrument to update the colors for.
403
+ * @param {DataSeriesType} chartType - The type of chart to update the series to.
404
+ * @returns {void}
405
+ */
406
+ updateSecondaryCandleSeriesConfig(config, instrumentSymbol, chartType) {
407
+ const candleSeriesConfig = mergeObj(config, getDefaultConfig().colors);
408
+ this.secondaryChartColors.updateColorConfig(instrumentSymbol, candleSeriesConfig);
409
+ const seriesToUpdate = this.findSecondarySeriesBySymbol(instrumentSymbol);
410
+ if (seriesToUpdate) {
411
+ seriesToUpdate.config.type = chartType;
412
+ seriesToUpdate.updateCandleSeriesColors(candleSeriesConfig);
413
+ this.bus.fireDraw([this.canvasModel.canvasId]);
414
+ }
415
+ this.bus.fireDraw([this.canvasModel.canvasId]);
416
+ }
417
+ /**
418
+ * Sets the autoScale property of the scaleModel object.
419
+ * @param {boolean} auto - The value to be set for the autoScale property.
420
+ * @returns {void}
421
+ */
422
+ setAutoScale(auto) {
423
+ this.scale.autoScale(auto);
424
+ }
425
+ /**
426
+ * Returns the effective width of the Y axis.
427
+ *
428
+ * @function
429
+ * @name getEffectiveYAxisWidth
430
+ * @returns {number} The effective width of the Y axis.
431
+ */
432
+ getEffectiveYAxisWidth() {
433
+ const yAxis = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID_Y_AXIS(CHART_UUID));
434
+ return yAxis.width;
435
+ }
436
+ /**
437
+ * Returns the effective width of the chart.
438
+ *
439
+ * @function
440
+ * @returns {number} The effective width of the chart.
441
+ */
442
+ getEffectiveChartWidth() {
443
+ const chart = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID(CHART_UUID));
444
+ return chart.width;
445
+ }
446
+ /**
447
+ * Returns the effective height of the chart.
448
+ *
449
+ * @returns {number} The effective height of the chart.
450
+ */
451
+ getEffectiveChartHeight() {
452
+ const chart = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID(CHART_UUID));
453
+ return chart.height;
454
+ }
455
+ /**
456
+ * Updates the offsets of the chart components and redraws the chart.
457
+ * @param {Partial<ChartConfigComponentsOffsets>} offsets - The new offsets to be applied to the chart components.
458
+ * @returns {void}
459
+ */
460
+ setOffsets(offsets) {
461
+ this.scale.updateOffsets(offsets);
462
+ const lastIdx = this.getCandlesCountWithRightOffset();
463
+ const visualCandles = this.mainCandleSeries.visualPoints;
464
+ if (this.hasCandles() && lastIdx >= visualCandles.length) {
465
+ this.scale.setXScale(this.scale.xStart, this.candleFromIdx(lastIdx).startUnit);
466
+ }
467
+ this.offsetsChanged.next();
468
+ this.bus.fireDraw();
469
+ }
470
+ /**
471
+ * Returns the offsets of the chart components.
472
+ * @returns {ChartConfigComponentsOffsets} The offsets of the chart components.
473
+ */
474
+ getOffsets() {
475
+ return this.scale.getOffsets();
476
+ }
477
+ /**
478
+ * Converts "y" in pixels to: price / percent / other value.
479
+ * @param y - source value in pixels
480
+ */
481
+ fromY(y) {
482
+ return this.scale.fromY(y);
483
+ }
484
+ /**
485
+ * Converts "y" in pixels to price
486
+ * @param y - source value in pixels
487
+ * @param candleSeriesModel - (optional) candle series
488
+ */
489
+ priceFromY(y, candleSeriesModel) {
490
+ const series = candleSeriesModel !== null && candleSeriesModel !== void 0 ? candleSeriesModel : this.mainCandleSeries;
491
+ return series.view.priceFromY(y);
492
+ }
493
+ /**
494
+ * Converts "x" in pixels to timestamp
495
+ * @param x - source value in pixels
496
+ */
497
+ fromX(x) {
498
+ return this.scale.fromX(x);
499
+ }
500
+ /**
501
+ * Converts index to pixel.
502
+ * @param idx - index of candle
503
+ */
504
+ toX(idx) {
505
+ const visualCandle = this.candleFromIdx(idx);
506
+ // lineX is the middle of candle - it's correct
507
+ return this.scale.toX(visualCandle.centerUnit);
508
+ }
509
+ /**
510
+ * Transforms X coordinate (relative to canvas element) to Candle object.
511
+ * If extrapolate = false, then it takes leftmost/rightmost existing candle
512
+ */
513
+ candleFromX(x, extrapolate = false, selectedCandleSeries = this.mainCandleSeries) {
514
+ const unit = this.scale.fromX(x);
515
+ return this.candleFromUnit(unit, extrapolate, selectedCandleSeries);
516
+ }
517
+ /**
518
+ * Returns a candle object based on the provided unit, which is searched for in the visualPoints array of the selectedCandleSeries.
519
+ * If extrapolate is true and the unit is outside the visualPoints array, a fake candle is returned.
520
+ * If extrapolate is false and the unit is outside the visualPoints array, null is returned.
521
+ * If the unit is within the visualPoints array, the corresponding candle object is returned.
522
+ *
523
+ * @param {Unit} unit - The unit to search for in the visualPoints array.
524
+ * @param {boolean} extrapolate - Whether to extrapolate a fake candle if the unit is outside the visualPoints array.
525
+ * @param {CandleSeriesModel} selectedCandleSeries - The candle series to search in. Defaults to the mainCandleSeries.
526
+ * @returns {Candle} - The corresponding candle object, or null if extrapolate is false and the unit is outside the visualPoints array.
527
+ */
528
+ candleFromUnit(unit, extrapolate = false, selectedCandleSeries = this.mainCandleSeries) {
529
+ var _a, _b;
530
+ const result = binarySearch(selectedCandleSeries.visualPoints, unit, i => i.startUnit);
531
+ const visualCandleSource = selectedCandleSeries.visualPoints;
532
+ const lastVisualCandle = this.getLastVisualCandle();
533
+ if (visualCandleSource[result.index] !== undefined &&
534
+ (unit < 0 || (lastVisualCandle && unit > lastVisualCandle.startUnit + lastVisualCandle.width))) {
535
+ result.index += round((unit - visualCandleSource[result.index].centerUnit) / this.mainCandleSeries.meanCandleWidth);
536
+ }
537
+ const candleIdx = result.index;
538
+ const safeIdx = Math.max(Math.min(visualCandleSource.length - 1, candleIdx), 0);
539
+ if ((candleIdx < 0 || candleIdx >= visualCandleSource.length) && extrapolate) {
540
+ // fake candle
541
+ return fakeCandle(this.mainCandleSeries.dataPoints, candleIdx, this.chartBaseModel.period);
542
+ }
543
+ else {
544
+ // real candle
545
+ return ((_b = (_a = visualCandleSource[safeIdx]) === null || _a === void 0 ? void 0 : _a.candle) !== null && _b !== void 0 ? _b : fakeCandle(this.mainCandleSeries.dataPoints, safeIdx, this.chartBaseModel.period));
546
+ }
547
+ }
548
+ /**
549
+ * For given timestamp finds the closest candle in dataset.
550
+ * @param timestamp
551
+ */
552
+ candleFromTimestamp(timestamp, shouldExtrapolate = true) {
553
+ return this.chartBaseModel.dataFromTimestamp(timestamp, shouldExtrapolate);
554
+ }
555
+ /**
556
+ * For given index returns the closest visual candle, or fake candle with correct X coordinate.
557
+ * @param idx - index of candle
558
+ */
559
+ candleFromIdx(idx) {
560
+ return this.chartBaseModel.dataFromIdx(idx);
561
+ }
562
+ /**
563
+ * Check whether model is ready for drawing.
564
+ */
565
+ isReady() {
566
+ // Do not check canvas size: we should check width only when resize event has occurred
567
+ return this.canvasModel.isReady() && this.hasCandles();
568
+ }
569
+ /**
570
+ * You can use this method to determine logic of visual candle transformation for specified chart type.
571
+ * @param chartType
572
+ * @param calculator
573
+ */
574
+ registerCandlesTransformer(chartType, calculator) {
575
+ this.candlesTransformersByChartType[chartType] = calculator;
576
+ }
577
+ /**
578
+ * You can use this method to determine chart width calculation for specified chart type.
579
+ * @param chartType
580
+ * @param calculator
581
+ */
582
+ registerCandlesWidthCalculator(chartType, calculator) {
583
+ this.candleWidthByChartType[chartType] = calculator;
584
+ }
585
+ /**
586
+ * You can use this method to modify labels for last candle.
587
+ * @param chartType
588
+ * @param handler
589
+ */
590
+ registerLastCandleLabelHandler(chartType, handler) {
591
+ this.lastCandleLabelsByChartType[chartType] = handler;
592
+ }
593
+ /**
594
+ * Checks if the main candle series has visual points.
595
+ * @returns {boolean} Returns true if the main candle series has visual points, otherwise false.
596
+ */
597
+ hasCandles() {
598
+ return this.mainCandleSeries.visualPoints.length !== 0;
599
+ }
600
+ /**
601
+ * Returns a visual candle object from the main candle series based on the provided index.
602
+ * @param {Index} idx - The index of the visual candle to retrieve.
603
+ * @returns {VisualCandle|undefined} - The visual candle object or undefined if it doesn't exist.
604
+ */
605
+ getVisualCandle(idx) {
606
+ var _a, _b, _c;
607
+ const indexToGrab = idx - ((_c = (_b = (_a = this.mainCandleSeries.visualPoints[0]) === null || _a === void 0 ? void 0 : _a.candle) === null || _b === void 0 ? void 0 : _b.idx) !== null && _c !== void 0 ? _c : 0);
608
+ return this.mainCandleSeries.visualPoints[indexToGrab];
609
+ }
610
+ /**
611
+ * Returns the index of the first data point in the main candle series.
612
+ *
613
+ * @returns {number} The index of the first data point in the main candle series.
614
+ */
615
+ getFirstIdx() {
616
+ return this.mainCandleSeries.dataIdxStart;
617
+ }
618
+ /**
619
+ * Returns the last index of the data in the mainCandleSeries.
620
+ *
621
+ * @returns {number} - The last index of the data in the mainCandleSeries.
622
+ */
623
+ getLastIdx() {
624
+ return this.mainCandleSeries.dataIdxEnd;
625
+ }
626
+ /**
627
+ * Returns the timestamp of the first candle in the viewport dataset
628
+ * @param dataBased - if false will return timestamp which matches first viewport point even if candle is not available
629
+ * @returns {Timestamp} The timestamp of the first candle
630
+ */
631
+ getFirstTimestamp(dataBased = true) {
632
+ if (dataBased) {
633
+ return this.candleFromIdx(this.getFirstIdx()).candle.timestamp;
634
+ }
635
+ else {
636
+ return this.candleFromUnit(this.scale.xStart, true).timestamp;
637
+ }
638
+ }
639
+ /**
640
+ * Returns the timestamp of the last candle in the viewport candle array
641
+ * @param dataBased - if false will return timestamp which matches first viewport point even if candle is not available
642
+ * @returns {Timestamp} The timestamp of the last candle
643
+ */
644
+ getLastTimestamp(dataBased = true) {
645
+ if (dataBased) {
646
+ return this.candleFromIdx(this.getLastIdx()).candle.timestamp;
647
+ }
648
+ else {
649
+ return this.candleFromUnit(this.scale.xEnd, true).timestamp;
650
+ }
651
+ }
652
+ /**
653
+ * Sets the timestamp range of the chart by setting the x-axis scale.
654
+ * @param {Timestamp} start - The start timestamp of the range.
655
+ * @param {Timestamp} end - The end timestamp of the range.
656
+ * @returns {void}
657
+ */
658
+ setTimestampRange(start, end) {
659
+ const startUnit = this.candleFromTimestamp(start).startUnit;
660
+ const endCandle = this.candleFromTimestamp(end);
661
+ const endUnit = endCandle.startUnit + endCandle.width;
662
+ return this.scale.setXScale(startUnit, endUnit);
663
+ }
664
+ /**
665
+ * Returns the last candle of the main candle series.
666
+ * @returns {Candle | undefined} The last candle of the main candle series or undefined if the series is empty.
667
+ */
668
+ getLastCandle() {
669
+ const candles = this.mainCandleSeries.dataPoints;
670
+ return lastOf(candles);
671
+ }
672
+ /**
673
+ * Returns the last visual candle of the main candle series.
674
+ * @returns {VisualCandle | undefined} The last visual candle of the main candle series or undefined if the series is empty.
675
+
676
+ */
677
+ getLastVisualCandle() {
678
+ const candles = this.mainCandleSeries.visualPoints;
679
+ return lastOf(candles);
680
+ }
681
+ /**
682
+ * Calculates the maximum number of candles that can fit in the chart width based on the minimum candle width
683
+ * @returns {number} - The maximum number of candles that can fit in the chart width
684
+ */
685
+ getMaxCandlesFitLength() {
686
+ return floor(this.getEffectiveChartWidth() / this.config.components.chart.minWidth);
687
+ }
688
+ /**
689
+ * Returns an array of CandleSeriesModel objects representing the secondary candle series.
690
+ * @returns {Array<CandleSeriesModel>} An array of CandleSeriesModel objects representing the secondary candle series.
691
+ */
692
+ getSecondarySeries() {
693
+ return this.secondaryCandleSeries;
694
+ }
695
+ /**
696
+ * Checks if a given symbol matches the symbol of a given CandleSeriesModel's instrument.
697
+ * @param {CandleSeriesModel} series - The CandleSeriesModel to check.
698
+ * @param {ChartInstrument['symbol']} symbol - The symbol to compare with the instrument's symbol.
699
+ * @returns {boolean} - Returns true if the symbol matches the instrument's symbol, false otherwise.
700
+ */
701
+ isSeriesInstrument(series, symbol) {
702
+ return series.instrument.symbol === symbol;
703
+ }
704
+ /**
705
+ * Returns an array of CandleSeriesModel objects that match the provided symbol.
706
+ *
707
+ * @param {string} symbol - The symbol to search for.
708
+ * @returns {CandleSeriesModel[]} - An array of CandleSeriesModel objects that match the provided symbol.
709
+ */
710
+ findSeriesBySymbol(symbol) {
711
+ return this.candleSeries.filter(series => this.isSeriesInstrument(series, symbol));
712
+ }
713
+ /**
714
+ * Finds a secondary candle series by symbol
715
+ *
716
+ * @param {string} symbol - The symbol of the chart instrument
717
+ * @returns {CandleSeriesModel | undefined} - The secondary candle series or undefined if not found
718
+ */
719
+ findSecondarySeriesBySymbol(symbol) {
720
+ return this.secondaryCandleSeries.find(series => this.isSeriesInstrument(series, symbol));
721
+ }
722
+ /**
723
+ * Reindexes candles based on a given series.
724
+ * @private
725
+ * @param {Array<Candle>} baseSeries - The base series to search for candles.
726
+ * @param {Array<Candle>} series - The series to reindex.
727
+ * @returns {Array<Candle>} - The reindexed series.
728
+ */
729
+ reindexCandlesBasedOnSeries(baseSeries, series) {
730
+ return series.reduce((candles, candle) => {
731
+ const timestamp = candle.timestamp;
732
+ // find index of candle in baseSeries
733
+ const result = searchCandleIndex(timestamp, false, baseSeries, this.chartBaseModel.period);
734
+ if (result.index >= 0 && result.index < baseSeries.length) {
735
+ candle.idx = result.index;
736
+ candles[result.index] = candle;
737
+ }
738
+ return candles;
739
+ }, []);
740
+ }
741
+ getPeriod() {
742
+ return this.chartBaseModel.period;
743
+ }
744
+ /**
745
+ * Checks if a given candle is within the viewport.
746
+ * @param {number} idx - The index of the candle to check.
747
+ * @returns {boolean} - True if the candle is within the viewport, false otherwise.
748
+ */
749
+ isCandleInViewport(idx) {
750
+ return this.getFirstIdx() <= idx && idx <= this.getLastIdx();
751
+ }
752
+ /**
753
+ * Updates candles in series. Default is main series.
754
+ * Any number of candles may be provided - they would be matched by their index and updated.
755
+ * @param candles - any list of new (updated) candles
756
+ * @param instrument - name of instrument to update
757
+ */
758
+ // I'd like to keep this method, for me one generic method is more convenient than 3 (updateLastCandle, addLastCandle, prepend...)
759
+ updateCandles(candles, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
760
+ const isMainSymbol = this.mainCandleSeries.instrument.symbol === instrumentSymbol;
761
+ const seriesList = this.findSeriesBySymbol(instrumentSymbol);
762
+ if (seriesList.length === 0) {
763
+ console.warn("updateCandles failed. Can't find series", instrumentSymbol);
764
+ return;
765
+ }
766
+ seriesList.forEach(series => {
767
+ const curCandles = series.dataPoints;
768
+ let isNewCandle = false;
769
+ let isInView = false;
770
+ let lastCandle;
771
+ candles.forEach(candle => {
772
+ var _a;
773
+ if (!candle) {
774
+ return;
775
+ }
776
+ // detect index of updating candle
777
+ const result = searchCandleIndex(candle.timestamp, true, curCandles, this.getPeriod());
778
+ const idx = Math.min(result.index, curCandles.length);
779
+ isNewCandle = isNewCandle || idx === curCandles.length;
780
+ // update the candle and index
781
+ curCandles[idx] = candle;
782
+ candle.idx = idx;
783
+ // set serie with new candle
784
+ series.dataPoints = curCandles;
785
+ series.recalculateDataViewportIndexes();
786
+ isInView = isInView || this.isCandleInViewport(idx);
787
+ const isOutRangeCurrentCandles = idx >= curCandles.length - 1;
788
+ const isBeforeCurrentLastCandle = lastCandle && candle.timestamp < lastCandle.timestamp;
789
+ if (isOutRangeCurrentCandles && !isBeforeCurrentLastCandle) {
790
+ lastCandle = candle;
791
+ }
792
+ // we can move chart only when update is for main symbol
793
+ // TODO we can have two series with the same instruments - this logic doesn't cover this case
794
+ if (isNewCandle && lastCandle && isMainSymbol && isInView) {
795
+ const widthCalculator = (_a = this.candleWidthByChartType[this.config.components.chart.type]) !== null && _a !== void 0 ? _a : calculateCandleWidth;
796
+ this.scale.moveXStart(this.scale.xStart + widthCalculator(lastCandle));
797
+ }
798
+ });
799
+ if (lastCandle) {
800
+ series.updateCurrentPrice(lastCandle.close);
801
+ }
802
+ if (isInView && lastCandle && candles.length === 1) {
803
+ // can apply some optimization
804
+ // series.recalculateOnlyLastVisualCandle();
805
+ // TODO apply optimization
806
+ this.bus.fireDraw([this.canvasModel.canvasId]);
807
+ }
808
+ else {
809
+ series.recalculateVisualPoints();
810
+ }
811
+ });
812
+ this.scale.doAutoScale();
813
+ this.candlesUpdatedSubject.next();
814
+ }
815
+ /**
816
+ * Triggers when candles set or updated
817
+ */
818
+ observeCandlesChanged() {
819
+ return merge(this.candlesSetSubject, this.candlesUpdatedSubject);
820
+ }
821
+ /**
822
+ * Returns an array of Candle objects representing the data points of the main candle series.
823
+ * @returns {Array<Candle>} An array of Candle objects.
824
+ */
825
+ getCandles() {
826
+ return this.mainCandleSeries.dataPoints;
827
+ }
828
+ /***
829
+ * Returns candles array which consists of real candles and fake candles if from and to can't be satisfied with real ones.
830
+ * @param from - if not specified set to first candle timestamp
831
+ * @param to - if not specified set to last candle timestamp + right offset
832
+ */
833
+ getCandlesWithFake(from = 0, to) {
834
+ let candles = this.getCandles().slice();
835
+ const candlesCount = this.getCandlesCount();
836
+ const _to = to !== null && to !== void 0 ? to : candlesCount + this.FAKE_CANDLES_DEFAULT;
837
+ candles = candles.slice(Math.max(0, from), Math.min(candlesCount, _to));
838
+ // add fake candles if needed
839
+ const append = [];
840
+ const prepend = [];
841
+ for (let i = candlesCount; i < _to; i++) {
842
+ append.push(fakeCandle(this.mainCandleSeries.dataPoints, i, this.getPeriod()));
843
+ }
844
+ const toPrepend = Math.min(0, _to);
845
+ for (let i = from; i < toPrepend; i++) {
846
+ prepend.push(fakeCandle(this.mainCandleSeries.dataPoints, i, this.getPeriod()));
847
+ }
848
+ return [...prepend, ...candles, ...append];
849
+ }
850
+ /**
851
+ * Returns the number of candles in the main candle series.
852
+ *
853
+ * @returns {number} The number of candles in the main candle series.
854
+ */
855
+ getCandlesCount() {
856
+ return this.mainCandleSeries.dataPoints.length;
857
+ }
858
+ /**
859
+ * Returns the number of candles with the right offset.
860
+ * @returns {number} - The number of candles with the right offset.
861
+ */
862
+ getCandlesCountWithRightOffset() {
863
+ return this.getCandlesCount() + this.getOffsets().right;
864
+ }
865
+ /**
866
+ * Clears the data of all candle series in the chart.
867
+ */
868
+ clearData() {
869
+ this.candleSeries.forEach(candleSeries => candleSeries.clearData());
870
+ }
871
+ /**
872
+ * Adds new candles array to the existing one at the start, mostly used in lazy loading
873
+ * @param target - initial candles array
874
+ * @param prependUpdate - additional candles array, which will be added to the target array
875
+ */
876
+ prependCandles(target, prependUpdate) {
877
+ const targetCopy = target.slice();
878
+ const prepend = [];
879
+ prependUpdate.forEach(c => {
880
+ const result = searchCandleIndex(c.timestamp, false, target);
881
+ const idx = result.index;
882
+ if (idx < 0) {
883
+ prepend.push(c);
884
+ }
885
+ else if (target[idx].timestamp === c.timestamp) {
886
+ targetCopy[idx] = c;
887
+ }
888
+ else {
889
+ console.warn(`Couldn't update candle with timestamp ${c.timestamp}`);
890
+ }
891
+ });
892
+ return {
893
+ prepended: prepend.length,
894
+ candles: [...prepend, ...targetCopy],
895
+ };
896
+ }
897
+ /**
898
+ * Adds new candle to the chart
899
+ * @param candle - new candle
900
+ * @param instrument - name of the instrument to update
901
+ */
902
+ addLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
903
+ this.updateCandles([candle], instrumentSymbol);
904
+ }
905
+ /**
906
+ * Updates last candle value
907
+ * @param candle - updated candle
908
+ * @param instrument - name of the instrument to update
909
+ */
910
+ updateLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
911
+ this.updateCandles([candle], instrumentSymbol);
912
+ }
913
+ }
914
+ const sortCandles = (candles) => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1));
915
+ const findFirstNotEmptyCandle = (candles, startIdx, iterateStep) => {
916
+ if (startIdx >= candles.length) {
917
+ return candles[candles.length - 1];
918
+ }
919
+ for (let i = startIdx; i < candles.length && i >= 0; i += iterateStep) {
920
+ const candle = candles[i];
921
+ if (candle) {
922
+ return candle;
923
+ }
924
+ }
925
+ };
926
+ /**
927
+ * Updates target array using update array.
928
+ * If there is a candle with the same timestamp as in target array then it will be replaced
929
+ * If the candle timestamp from update is somewhere between target candles then it will be ignored
930
+ * If the update candle timestamp is beyond target, then it will be prepended/appended to target
931
+ * @param target {Candle[]} - sorted candles
932
+ * @param update {Candle[]} - sorted candles
933
+ */
934
+ const updateCandles = (target, update) => {
935
+ const targetCopy = target.slice();
936
+ const prepend = [];
937
+ const append = [];
938
+ update.forEach(c => {
939
+ const result = searchCandleIndex(c.timestamp, true, target);
940
+ const idx = result.index;
941
+ if (idx < 0) {
942
+ prepend.push(c);
943
+ }
944
+ else if (idx >= target.length) {
945
+ append.push(c);
946
+ }
947
+ else if (target[idx].timestamp === c.timestamp) {
948
+ targetCopy[idx] = c;
949
+ }
950
+ else {
951
+ console.warn(`Couldn't update candle with timestamp ${c.timestamp}`);
952
+ }
953
+ });
954
+ return {
955
+ prepended: prepend.length,
956
+ appended: append.length,
957
+ candles: [...prepend, ...targetCopy, ...append],
958
+ };
959
+ };