@devexperts/dxcharts-lite 1.0.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +2 -2
  2. package/dist/chart/animation/canvas-animation.js +134 -1
  3. package/dist/chart/animation/types/animation.js +43 -1
  4. package/dist/chart/animation/types/color-alpha-animation.d.ts +1 -1
  5. package/dist/chart/animation/types/color-alpha-animation.js +60 -1
  6. package/dist/chart/animation/types/color-transition-animation.d.ts +1 -1
  7. package/dist/chart/animation/types/color-transition-animation.js +86 -1
  8. package/dist/chart/animation/types/viewport-movement-animation.js +63 -1
  9. package/dist/chart/animation/viewport-model-animation.js +20 -1
  10. package/dist/chart/bootstrap.d.ts +51 -48
  11. package/dist/chart/bootstrap.js +449 -1
  12. package/dist/chart/canvas/canvas-bounds-container.d.ts +0 -5
  13. package/dist/chart/canvas/canvas-bounds-container.js +815 -1
  14. package/dist/chart/canvas/canvas-chart-html.js +16 -18
  15. package/dist/chart/canvas/chart-elements.d.ts +1 -4
  16. package/dist/chart/canvas/chart-elements.js +22 -1
  17. package/dist/chart/canvas/cursor.handler.js +122 -1
  18. package/dist/chart/canvas/layout-creator.js +34 -1
  19. package/dist/chart/canvas/y-axis-bounds.container.d.ts +2 -2
  20. package/dist/chart/canvas/y-axis-bounds.container.js +67 -1
  21. package/dist/chart/chart-container.js +1 -1
  22. package/dist/chart/chart.config.d.ts +4 -5
  23. package/dist/chart/chart.config.js +645 -1
  24. package/dist/chart/chart.d.ts +62 -0
  25. package/dist/chart/chart.js +106 -0
  26. package/dist/chart/components/chart/basic-scale.d.ts +2 -2
  27. package/dist/chart/components/chart/basic-scale.js +31 -1
  28. package/dist/chart/components/chart/candle-transformer.functions.js +15 -1
  29. package/dist/chart/components/chart/candle-width-calculator.functions.js +2 -1
  30. package/dist/chart/components/chart/candle.functions.js +44 -1
  31. package/dist/chart/components/chart/chart-area-pan.handler.d.ts +3 -3
  32. package/dist/chart/components/chart/chart-area-pan.handler.js +197 -1
  33. package/dist/chart/components/chart/chart-base.model.js +66 -1
  34. package/dist/chart/components/chart/chart.component.d.ts +7 -3
  35. package/dist/chart/components/chart/chart.component.js +408 -1
  36. package/dist/chart/components/chart/chart.model.d.ts +4 -11
  37. package/dist/chart/components/chart/chart.model.js +954 -1
  38. package/dist/chart/components/chart/data-series.high-low-provider.js +34 -1
  39. package/dist/chart/components/chart/fake-candles.js +97 -1
  40. package/dist/chart/components/chart/price.formatter.js +35 -1
  41. package/dist/chart/components/chart/secondary-chart-colors-pool.js +68 -1
  42. package/dist/chart/components/cross_tool/cross-tool.component.js +85 -1
  43. package/dist/chart/components/cross_tool/cross-tool.drawer.js +32 -1
  44. package/dist/chart/components/cross_tool/cross-tool.model.js +107 -1
  45. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +137 -1
  46. package/dist/chart/components/cross_tool/types/none.drawer.js +3 -1
  47. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-x.component.js +28 -1
  48. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-y.component.js +24 -1
  49. package/dist/chart/components/dran-n-drop_helper/drag-n-drop.component.js +53 -1
  50. package/dist/chart/components/dynamic-objects/dynamic-objects.component.d.ts +13 -0
  51. package/dist/chart/components/dynamic-objects/dynamic-objects.component.js +20 -0
  52. package/dist/chart/components/dynamic-objects/dynamic-objects.drawer.d.ts +18 -0
  53. package/dist/chart/components/dynamic-objects/dynamic-objects.drawer.js +23 -0
  54. package/dist/chart/components/dynamic-objects/dynamic-objects.model.d.ts +63 -0
  55. package/dist/chart/components/dynamic-objects/dynamic-objects.model.js +136 -0
  56. package/dist/chart/components/events/events-hit-test.drawer.js +63 -1
  57. package/dist/chart/components/events/events.component.js +61 -1
  58. package/dist/chart/components/events/events.drawer.js +195 -1
  59. package/dist/chart/components/events/events.model.js +69 -1
  60. package/dist/chart/components/grid/grid.component.d.ts +2 -2
  61. package/dist/chart/components/grid/grid.component.js +31 -1
  62. package/dist/chart/components/grid/grid.drawer.d.ts +4 -3
  63. package/dist/chart/components/grid/grid.drawer.js +106 -1
  64. package/dist/chart/components/high_low/high-low.component.js +12 -1
  65. package/dist/chart/components/high_low/high-low.drawer.js +126 -1
  66. package/dist/chart/components/highlights/highlights.component.js +46 -1
  67. package/dist/chart/components/highlights/highlights.drawer.js +154 -1
  68. package/dist/chart/components/highlights/highlights.model.js +75 -1
  69. package/dist/chart/components/labels_generator/numeric-axis-labels.generator.d.ts +1 -1
  70. package/dist/chart/components/labels_generator/numeric-axis-labels.generator.js +199 -1
  71. package/dist/chart/components/navigation_map/navigation-map-move.handler.d.ts +2 -2
  72. package/dist/chart/components/navigation_map/navigation-map-move.handler.js +108 -1
  73. package/dist/chart/components/navigation_map/navigation-map.component.js +112 -1
  74. package/dist/chart/components/navigation_map/navigation-map.drawer.js +244 -1
  75. package/dist/chart/components/navigation_map/navigation-map.model.js +33 -2
  76. package/dist/chart/components/pan/chart-pan.component.d.ts +2 -2
  77. package/dist/chart/components/pan/chart-pan.component.js +51 -1
  78. package/dist/chart/components/pane/extent/y-extent-component.d.ts +12 -18
  79. package/dist/chart/components/pane/extent/y-extent-component.js +120 -1
  80. package/dist/chart/components/pane/pane-hit-test.controller.d.ts +2 -2
  81. package/dist/chart/components/pane/pane-hit-test.controller.js +55 -1
  82. package/dist/chart/components/pane/pane-manager.component.d.ts +12 -6
  83. package/dist/chart/components/pane/pane-manager.component.js +149 -1
  84. package/dist/chart/components/pane/pane.component.d.ts +16 -32
  85. package/dist/chart/components/pane/pane.component.js +278 -1
  86. package/dist/chart/components/resizer/bar-resizer.component.js +139 -1
  87. package/dist/chart/components/resizer/bar-resizer.drawer.js +46 -1
  88. package/dist/chart/components/snapshot/snapshot.component.js +48 -1
  89. package/dist/chart/components/volumes/separate-volumes.component.d.ts +6 -10
  90. package/dist/chart/components/volumes/separate-volumes.component.js +63 -1
  91. package/dist/chart/components/volumes/volume-color-resolvers.functions.js +18 -1
  92. package/dist/chart/components/volumes/volumes.component.d.ts +6 -7
  93. package/dist/chart/components/volumes/volumes.component.js +94 -1
  94. package/dist/chart/components/volumes/volumes.drawer.d.ts +5 -12
  95. package/dist/chart/components/volumes/volumes.drawer.js +140 -1
  96. package/dist/chart/components/volumes/volumes.formatter.js +31 -1
  97. package/dist/chart/components/volumes/volumes.model.d.ts +2 -2
  98. package/dist/chart/components/volumes/volumes.model.js +43 -1
  99. package/dist/chart/components/watermark/water-mark.component.js +103 -1
  100. package/dist/chart/components/watermark/water-mark.drawer.js +187 -1
  101. package/dist/chart/components/x_axis/numeric-x-axis-labels.generator.js +27 -1
  102. package/dist/chart/components/x_axis/time/parser/time-formats-matchers.functions.js +187 -1
  103. package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.js +76 -1
  104. package/dist/chart/components/x_axis/time/parser/time-formats-validators.functions.js +79 -1
  105. package/dist/chart/components/x_axis/time/parser/time-formats.model.js +14 -1
  106. package/dist/chart/components/x_axis/time/x-axis-weights.functions.d.ts +1 -1
  107. package/dist/chart/components/x_axis/time/x-axis-weights.functions.js +143 -1
  108. package/dist/chart/components/x_axis/time/x-axis-weights.generator.js +73 -1
  109. package/dist/chart/components/x_axis/x-axis-draw.functions.js +49 -1
  110. package/dist/chart/components/x_axis/x-axis-labels.drawer.js +70 -1
  111. package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +2 -2
  112. package/dist/chart/components/x_axis/x-axis-labels.generator.js +332 -1
  113. package/dist/chart/components/x_axis/x-axis-labels.model.js +35 -1
  114. package/dist/chart/components/x_axis/x-axis-scale.handler.d.ts +2 -2
  115. package/dist/chart/components/x_axis/x-axis-scale.handler.js +60 -1
  116. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +82 -1
  117. package/dist/chart/components/x_axis/x-axis.component.d.ts +2 -2
  118. package/dist/chart/components/x_axis/x-axis.component.js +119 -1
  119. package/dist/chart/components/y_axis/label-color.functions.js +53 -1
  120. package/dist/chart/components/y_axis/numeric-y-axis-labels.generator.d.ts +4 -4
  121. package/dist/chart/components/y_axis/numeric-y-axis-labels.generator.js +33 -1
  122. package/dist/chart/components/y_axis/price_labels/data-series-y-axis-labels.provider.d.ts +3 -3
  123. package/dist/chart/components/y_axis/price_labels/data-series-y-axis-labels.provider.js +67 -1
  124. package/dist/chart/components/y_axis/price_labels/labels-positions-calculator.js +56 -1
  125. package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.d.ts +4 -3
  126. package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.js +96 -1
  127. package/dist/chart/components/y_axis/price_labels/price-label.drawer.d.ts +2 -2
  128. package/dist/chart/components/y_axis/price_labels/price-label.drawer.js +119 -1
  129. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.d.ts +9 -8
  130. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.js +201 -1
  131. package/dist/chart/components/y_axis/price_labels/y-axis-price-labels.drawer.d.ts +6 -7
  132. package/dist/chart/components/y_axis/price_labels/y-axis-price-labels.drawer.js +58 -1
  133. package/dist/chart/components/y_axis/y-axis-base-labels.model.d.ts +6 -4
  134. package/dist/chart/components/y_axis/y-axis-base-labels.model.js +47 -1
  135. package/dist/chart/components/y_axis/y-axis-labels.drawer.d.ts +4 -4
  136. package/dist/chart/components/y_axis/y-axis-labels.drawer.js +161 -1
  137. package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +2 -2
  138. package/dist/chart/components/y_axis/y-axis-scale.handler.js +72 -1
  139. package/dist/chart/components/y_axis/y-axis.component.d.ts +32 -41
  140. package/dist/chart/components/y_axis/y-axis.component.js +220 -1
  141. package/dist/chart/components/y_axis/y-axis.drawer.d.ts +9 -12
  142. package/dist/chart/components/y_axis/y-axis.drawer.js +96 -1
  143. package/dist/chart/components/y_axis/y-axis.model.d.ts +10 -17
  144. package/dist/chart/components/y_axis/y-axis.model.js +34 -1
  145. package/dist/chart/drawers/chart-background.drawer.js +69 -1
  146. package/dist/chart/drawers/chart-type-drawers/area.drawer.js +69 -1
  147. package/dist/chart/drawers/chart-type-drawers/bar.drawer.js +57 -1
  148. package/dist/chart/drawers/chart-type-drawers/baseline.drawer.js +84 -1
  149. package/dist/chart/drawers/chart-type-drawers/candle.drawer.js +162 -1
  150. package/dist/chart/drawers/chart-type-drawers/histogram.drawer.js +57 -1
  151. package/dist/chart/drawers/chart-type-drawers/line.drawer.js +38 -1
  152. package/dist/chart/drawers/chart-type-drawers/scatter-plot.drawer.js +19 -1
  153. package/dist/chart/drawers/clear-canvas.drawer.js +14 -1
  154. package/dist/chart/drawers/composite.drawer.js +67 -1
  155. package/dist/chart/drawers/data-series-drawers/candle-series-wrapper.js +50 -1
  156. package/dist/chart/drawers/data-series-drawers/color-candle.drawer.js +35 -1
  157. package/dist/chart/drawers/data-series-drawers/data-series-drawers.utils.js +16 -1
  158. package/dist/chart/drawers/data-series-drawers/difference-cloud.drawer.js +106 -1
  159. package/dist/chart/drawers/data-series-drawers/histogram.drawer.js +23 -1
  160. package/dist/chart/drawers/data-series-drawers/linear.drawer.js +19 -1
  161. package/dist/chart/drawers/data-series-drawers/points.drawer.js +19 -1
  162. package/dist/chart/drawers/data-series-drawers/rectangular-tool.drawer.js +7 -1
  163. package/dist/chart/drawers/data-series-drawers/text.drawer.js +25 -1
  164. package/dist/chart/drawers/data-series-drawers/trend-histogram.drawer.js +35 -1
  165. package/dist/chart/drawers/data-series-drawers/triangle.drawer.js +22 -1
  166. package/dist/chart/drawers/data-series.drawer.d.ts +5 -7
  167. package/dist/chart/drawers/data-series.drawer.js +56 -1
  168. package/dist/chart/drawers/drawing-manager.d.ts +1 -1
  169. package/dist/chart/drawers/drawing-manager.js +177 -1
  170. package/dist/chart/drawers/ht-data-series.drawer.js +37 -1
  171. package/dist/chart/events/event-bus.js +73 -1
  172. package/dist/chart/events/events.js +3 -1
  173. package/dist/chart/inputhandlers/candle-tap.handler.js +46 -1
  174. package/dist/chart/inputhandlers/chart-resize.handler.js +98 -1
  175. package/dist/chart/inputhandlers/cross-event-producer.component.js +67 -1
  176. package/dist/chart/inputhandlers/hover-producer.component.d.ts +2 -2
  177. package/dist/chart/inputhandlers/hover-producer.component.js +228 -1
  178. package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +2 -2
  179. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +80 -1
  180. package/dist/chart/inputlisteners/canvas-input-listener.component.js +629 -1
  181. package/dist/chart/model/baseline.model.js +88 -1
  182. package/dist/chart/model/bounds.model.js +1 -1
  183. package/dist/chart/model/candle-hover.js +70 -1
  184. package/dist/chart/model/candle-series-high-low.provider.js +45 -1
  185. package/dist/chart/model/candle-series.model.d.ts +3 -3
  186. package/dist/chart/model/candle-series.model.js +245 -1
  187. package/dist/chart/model/candle.model.js +69 -1
  188. package/dist/chart/model/canvas.model.js +228 -1
  189. package/dist/chart/model/chart-base-element.js +129 -1
  190. package/dist/chart/model/compare-series-hover.js +25 -1
  191. package/dist/chart/model/data-series-view.d.ts +5 -5
  192. package/dist/chart/model/data-series-view.js +111 -1
  193. package/dist/chart/model/data-series.config.js +14 -1
  194. package/dist/chart/model/data-series.model.d.ts +4 -4
  195. package/dist/chart/model/data-series.model.js +281 -1
  196. package/dist/chart/model/date-time.formatter.js +151 -1
  197. package/dist/chart/model/hit-test-canvas.model.d.ts +1 -1
  198. package/dist/chart/model/hit-test-canvas.model.js +256 -1
  199. package/dist/chart/model/main-candle-series.model.d.ts +1 -1
  200. package/dist/chart/model/main-candle-series.model.js +29 -1
  201. package/dist/chart/model/scale.model.d.ts +3 -2
  202. package/dist/chart/model/scale.model.js +316 -1
  203. package/dist/chart/model/scaling/auto-scale.model.d.ts +2 -4
  204. package/dist/chart/model/scaling/auto-scale.model.js +91 -1
  205. package/dist/chart/model/scaling/constrait.functions.js +61 -1
  206. package/dist/chart/model/scaling/lock-ratio.model.js +17 -1
  207. package/dist/chart/model/scaling/move-chart.functions.js +22 -1
  208. package/dist/chart/model/scaling/viewport.model.d.ts +2 -2
  209. package/dist/chart/model/scaling/viewport.model.js +279 -1
  210. package/dist/chart/model/scaling/x-zooming.functions.js +35 -1
  211. package/dist/chart/model/time-zone.model.js +109 -1
  212. package/dist/chart/model/visual-candle.js +134 -1
  213. package/dist/chart/utils/__tests__/array.utils.test.js +135 -1
  214. package/dist/chart/utils/__tests__/math.utils.test.js +14 -1
  215. package/dist/chart/utils/__tests__/object.utils.test.js +11 -1
  216. package/dist/chart/utils/__tests__/priceIncrementsUtils.test.js +29 -1
  217. package/dist/chart/utils/array.utils.d.ts +1 -1
  218. package/dist/chart/utils/array.utils.js +269 -1
  219. package/dist/chart/utils/auto-period-detector.utils.js +39 -1
  220. package/dist/chart/utils/candles-generator-ts.utils.js +20 -1
  221. package/dist/chart/utils/candles-generator.utils.js +161 -1
  222. package/dist/chart/utils/candles.utils.js +42 -1
  223. package/dist/chart/utils/canvas/canvas-drawing-functions.utils.js +144 -1
  224. package/dist/chart/utils/canvas/canvas-font-measure-tool.utils.js +51 -1
  225. package/dist/chart/utils/canvas/canvas-text-functions.utils.js +156 -1
  226. package/dist/chart/utils/color.utils.js +31 -1
  227. package/dist/chart/utils/device/browser.utils.js +10 -1
  228. package/dist/chart/utils/device/device-detector.utils.js +24 -1
  229. package/dist/chart/utils/device/device-pixel-ratio.utils.js +21 -1
  230. package/dist/chart/utils/device/touchpad.utils.js +91 -1
  231. package/dist/chart/utils/dom.utils.js +15 -1
  232. package/dist/chart/utils/function.utils.js +16 -1
  233. package/dist/chart/utils/linkedList.utils.d.ts +28 -0
  234. package/dist/chart/utils/linkedList.utils.js +138 -0
  235. package/dist/chart/utils/math.utils.js +115 -1
  236. package/dist/chart/utils/merge.utils.js +56 -1
  237. package/dist/chart/utils/object.utils.js +43 -1
  238. package/dist/chart/utils/performance/animation-frame-cache.utils.js +77 -0
  239. package/dist/chart/utils/{perfomance → performance}/debounce.utils.js +7 -1
  240. package/dist/chart/utils/performance/memoize.utils.js +74 -0
  241. package/dist/chart/utils/performance/request-animation-frame-throttle.utils.js +43 -0
  242. package/dist/chart/utils/performance/throttle.utils.js +26 -0
  243. package/dist/chart/utils/price-increments.utils.d.ts +1 -0
  244. package/dist/chart/utils/price-increments.utils.js +127 -1
  245. package/dist/chart/utils/uuid.utils.js +4 -1
  246. package/dist/dxchart.min.js +9 -12
  247. package/dist/index.d.ts +3 -3
  248. package/dist/index.js +20 -1
  249. package/package.json +4 -4
  250. package/dist/chart/utils/perfomance/animation-frame-cache.utils.js +0 -6
  251. package/dist/chart/utils/perfomance/memoize.utils.js +0 -6
  252. package/dist/chart/utils/perfomance/request-animation-frame-throttle.utils.js +0 -6
  253. package/dist/chart/utils/perfomance/throttle.utils.js +0 -6
  254. /package/dist/chart/utils/{perfomance → performance}/animation-frame-cache.utils.d.ts +0 -0
  255. /package/dist/chart/utils/{perfomance → performance}/debounce.utils.d.ts +0 -0
  256. /package/dist/chart/utils/{perfomance → performance}/memoize.utils.d.ts +0 -0
  257. /package/dist/chart/utils/{perfomance → performance}/request-animation-frame-throttle.utils.d.ts +0 -0
  258. /package/dist/chart/utils/{perfomance → performance}/throttle.utils.d.ts +0 -0
@@ -3,4 +3,259 @@
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{merge as C,Subject as d}from"rxjs";import{map as m,throttleTime as E}from"rxjs/operators";import{CanvasElement as x}from"../canvas/canvas-bounds-container";import{CanvasModel as H,initCanvasWithConfig as L}from"./canvas.model";import{animationFrameId as g}from"../utils/perfomance/request-animation-frame-throttle.utils";const k=317;export const HIT_TEST_ID_RANGE={DRAWINGS:[1,199],NEWS:[200,299],DATA_SERIES:[300,2999],EVENTS:[3e3,4e3]};export class HitTestCanvasModel extends H{constructor(e,s,i,n,u,o,a,b){super(e,s,u,a,b,{willReadFrequently:!0,desynchronized:!0}),this.canvasInputListener=i,this.canvasBoundsContainer=n,this.hitTestSubscribers=[],this.eventsSubscriptions=[],this.hoverSubject=new d,this.touchStartSubject=new d,this.dblClickSubject=new d,this.rightClickSubject=new d,this.curImgData=new Uint8ClampedArray(4),this.prevAnimationFrameId=-1,L(this,o),s.style.visibility="hidden",this.enableUserControls()}enableUserControls(){if(this.eventsSubscriptions.length===0){const e=this.canvasBoundsContainer.getBoundsHitTest(x.ALL_PANES),s=this.canvasInputListener.observeMouseMove().pipe(E(100,void 0,{trailing:!0})).subscribe(r=>this.eventHandler(r,"hover")),i=this.canvasInputListener.observeTouchStart().pipe(m(()=>this.canvasInputListener.currentPoint)).subscribe(r=>this.eventHandler(r,"touchstart")),n=C(this.canvasInputListener.observeMouseDown(e),this.canvasInputListener.observeTouchStart().pipe(m(()=>this.canvasInputListener.currentPoint))).subscribe(r=>this.eventHandler(r,"mousedown")),u=C(this.canvasInputListener.observeMouseUp(e),this.canvasInputListener.observeTouchEndDocument().pipe(m(()=>this.canvasInputListener.currentPoint))).subscribe(r=>this.eventHandler(r,"mouseup")),o=this.canvasInputListener.observeDbClick(e).subscribe(r=>this.eventHandler(r,"dblclick")),a=this.canvasInputListener.observeContextMenu(e).pipe(m(()=>Object.assign({},this.canvasInputListener.currentPoint))).subscribe(r=>{this.eventHandler(r,"contextmenu")}),b=this.canvasInputListener.observeWheel(e).subscribe(r=>setTimeout(()=>this.eventHandler(r,"zoom"),0));this.eventsSubscriptions.push(s,n,o,a,b,i,u)}}disableUserControls(){this.eventsSubscriptions.forEach(e=>e.unsubscribe()),this.eventsSubscriptions=[]}addSubscriber(e){this.hitTestSubscribers.push(e)}removeSubscriber(e){this.hitTestSubscribers=this.hitTestSubscribers.filter(s=>s===e)}idToColor(e){const s=(e*k).toString(16);return"#000000".substr(0,7-s.length)+s}colorToId(e){return e/k}observeHoverOnElement(){return this.hoverSubject.asObservable()}observeTouchStartOnElement(){return this.touchStartSubject.asObservable()}observeDblClickOnElement(){return this.dblClickSubject.asObservable()}observeRightClickOnElement(){return this.rightClickSubject.asObservable()}getPixel(e,s){const i=window.devicePixelRatio;return this.prevAnimationFrameId!==g&&(this.curImgData=this.ctx.getImageData(e*i,s*i,1,1).data,this.prevAnimationFrameId=g),this.curImgData}resolveModel(e){const s=this.getPixel(e.x,e.y),i=this.colorToId(s[0]*65536+s[1]*256+s[2]),n=Number(i),[u]=p(this.hitTestSubscribers,n);return u==null?void 0:u.lookup(i)}resolveCursor(e){var s;if(!this.hitTestSubscribers.some(b=>b.resolveCursor!==void 0))return;const i=this.getPixel(e.x,e.y),n=this.colorToId(i[0]*65536+i[1]*256+i[2]),u=Number(n),[o]=p(this.hitTestSubscribers,u),a=o==null?void 0:o.lookup(n);return(s=o==null?void 0:o.resolveCursor)===null||s===void 0?void 0:s.call(o,e,a)}eventHandler(e,s){var i,n,u,o,a,b,r;const S=this.getPixel(e.x,e.y),I=this.colorToId(S[0]*65536+S[1]*256+S[2]),f=Number(I),[t,h]=p(this.hitTestSubscribers,f),c=t==null?void 0:t.lookup(I),v={point:e,model:c};switch(s){case"mousedown":c&&((i=t==null?void 0:t.onMouseDown)===null||i===void 0||i.call(t,c,e)),h.forEach(l=>l.onMouseDown&&l.onMouseDown(null,e));break;case"mouseup":c&&((n=t==null?void 0:t.onMouseUp)===null||n===void 0||n.call(t,c,e)),h.forEach(l=>l.onMouseUp&&l.onMouseUp(null,e));break;case"hover":c&&((u=t==null?void 0:t.onHover)===null||u===void 0||u.call(t,c,e)),h.forEach(l=>l.onHover&&l.onHover(null,e)),this.hoverSubject.next(v);break;case"touchstart":c&&((o=t==null?void 0:t.onTouchStart)===null||o===void 0||o.call(t,c,e)),h.forEach(l=>l.onTouchStart&&l.onTouchStart(null,e)),this.touchStartSubject.next(v);break;case"dblclick":c&&((a=t==null?void 0:t.onDblClick)===null||a===void 0||a.call(t,c,e)),this.dblClickSubject.next(v);break;case"contextmenu":c&&((b=t==null?void 0:t.onRightClick)===null||b===void 0||b.call(t,c,e)),this.rightClickSubject.next(v);break;case"zoom":c&&((r=t==null?void 0:t.onZoom)===null||r===void 0||r.call(t,c,e)),h.forEach(l=>l.onZoom&&l.onZoom(null,e));break;default:break}}}const p=(T,e)=>{let s;const i=[];return T.forEach(n=>{const[u,o]=n.getIdRange();e>=u&&e<=o?s=n:i.push(n)}),[s,i]};
6
+ import { merge, Subject } from 'rxjs';
7
+ import { map, throttleTime } from 'rxjs/operators';
8
+ import { CanvasElement } from '../canvas/canvas-bounds-container';
9
+ import { CanvasModel, initCanvasWithConfig } from './canvas.model';
10
+ import { animationFrameId } from '../utils/performance/request-animation-frame-throttle.utils';
11
+ const bigPrimeNumber = 317;
12
+ export const HIT_TEST_ID_RANGE = {
13
+ DRAWINGS: [1, 199],
14
+ NEWS: [200, 299],
15
+ DATA_SERIES: [300, 2999],
16
+ EVENTS: [3000, 4000],
17
+ EXECUTED_ORDERS: [4001, 5000],
18
+ };
19
+ /** HitTestCanvasModel
20
+ * Canvas layer for testing mouse events over the models such as Charts, Drawings, Volumes and etc.
21
+ * !!! always add new drawers to hit-test drawingManager BEFORE the DrawerType.HIT_TEST_DRAWINGS to save the hierarchy
22
+ *
23
+ * @doc-tags chart-core,hit-test
24
+ */
25
+ export class HitTestCanvasModel extends CanvasModel {
26
+ constructor(eventBus, canvas, canvasInputListener, canvasBoundsContainer, drawingManager, chartConfig, canvasModels, resizer) {
27
+ super(eventBus, canvas, drawingManager, canvasModels, resizer, {
28
+ willReadFrequently: true,
29
+ desynchronized: true,
30
+ });
31
+ this.canvasInputListener = canvasInputListener;
32
+ this.canvasBoundsContainer = canvasBoundsContainer;
33
+ this.hitTestSubscribers = [];
34
+ this.eventsSubscriptions = [];
35
+ this.hoverSubject = new Subject();
36
+ this.touchStartSubject = new Subject();
37
+ this.dblClickSubject = new Subject();
38
+ this.rightClickSubject = new Subject();
39
+ this.curImgData = new Uint8ClampedArray(4);
40
+ this.prevAnimationFrameId = -1;
41
+ initCanvasWithConfig(this, chartConfig);
42
+ canvas.style.visibility = 'hidden';
43
+ this.enableUserControls();
44
+ }
45
+ /**
46
+ * Enables HitTestCanvasModel events listeners.
47
+ */
48
+ enableUserControls() {
49
+ if (this.eventsSubscriptions.length === 0) {
50
+ const bounds = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
51
+ const hoverSub = this.canvasInputListener
52
+ .observeMouseMove()
53
+ .pipe(throttleTime(100, undefined, { trailing: true }))
54
+ .subscribe(point => this.eventHandler(point, 'hover'));
55
+ const touchStartSub = this.canvasInputListener
56
+ .observeTouchStart()
57
+ .pipe(map(() => this.canvasInputListener.currentPoint))
58
+ .subscribe(point => this.eventHandler(point, 'touchstart'));
59
+ const clickSub = merge(this.canvasInputListener.observeMouseDown(bounds),
60
+ // should probably be deleted, touch event is a separate event and sometimes it doesn't work while being a part of click event
61
+ this.canvasInputListener.observeTouchStart().pipe(map(() => this.canvasInputListener.currentPoint))).subscribe(point => this.eventHandler(point, 'mousedown'));
62
+ const mouseUpSub = merge(this.canvasInputListener.observeMouseUp(bounds),
63
+ // should probably be deleted, touch event is a separate event and sometimes it doesn't work while being a part of click event
64
+ this.canvasInputListener
65
+ .observeTouchEndDocument()
66
+ .pipe(map(() => this.canvasInputListener.currentPoint))).subscribe(point => this.eventHandler(point, 'mouseup'));
67
+ const dblClickSub = this.canvasInputListener
68
+ .observeDbClick(bounds)
69
+ .subscribe(point => this.eventHandler(point, 'dblclick'));
70
+ const rightClickSub = this.canvasInputListener
71
+ .observeContextMenu(bounds)
72
+ .pipe(map(() => (Object.assign({}, this.canvasInputListener.currentPoint))))
73
+ .subscribe(point => {
74
+ this.eventHandler(point, 'contextmenu');
75
+ });
76
+ const zoomSub = this.canvasInputListener
77
+ .observeWheel(bounds)
78
+ .subscribe(point => setTimeout(() => this.eventHandler(point, 'zoom'), 0));
79
+ this.eventsSubscriptions.push(hoverSub, clickSub, dblClickSub, rightClickSub, zoomSub, touchStartSub, mouseUpSub);
80
+ }
81
+ }
82
+ /**
83
+ * Disables HitTestCanvasModel events listeners.
84
+ */
85
+ disableUserControls() {
86
+ this.eventsSubscriptions.forEach(sub => sub.unsubscribe());
87
+ this.eventsSubscriptions = [];
88
+ }
89
+ /**
90
+ * Adds a new subscriber to the list of hit test subscribers.
91
+ * @param {HitTestSubscriber<unknown>} subscriber - The subscriber to be added.
92
+ * @returns {void}
93
+ */
94
+ addSubscriber(subscriber) {
95
+ this.hitTestSubscribers.push(subscriber);
96
+ }
97
+ /**
98
+ * Removes a subscriber from the list of hit test subscribers.
99
+ *
100
+ * @param {HitTestSubscriber<unknown>} subscriber - The subscriber to be removed.
101
+ * @returns {void}
102
+ */
103
+ removeSubscriber(subscriber) {
104
+ this.hitTestSubscribers = this.hitTestSubscribers.filter(sub => sub === subscriber);
105
+ }
106
+ /**
107
+ * Converts a number to a hexadecimal color code.
108
+ * @param {number} id - The number to be converted.
109
+ * @returns {string} - The hexadecimal color code.
110
+ */
111
+ idToColor(id) {
112
+ const hex = (id * bigPrimeNumber).toString(16);
113
+ return '#000000'.substr(0, 7 - hex.length) + hex;
114
+ }
115
+ /**
116
+ * This function takes a number representing a color and returns the corresponding ID by dividing it by a big prime number.
117
+ *
118
+ * @param {number} color - The number representing the color.
119
+ * @returns {number} - The ID corresponding to the color.
120
+ */
121
+ colorToId(color) {
122
+ return color / bigPrimeNumber;
123
+ }
124
+ /**
125
+ * Observes hovered on element event, provides hovered element model when move in.
126
+ */
127
+ observeHoverOnElement() {
128
+ return this.hoverSubject.asObservable();
129
+ }
130
+ /**
131
+ * Observes touch start on element event, provides element model.
132
+ */
133
+ observeTouchStartOnElement() {
134
+ return this.touchStartSubject.asObservable();
135
+ }
136
+ /**
137
+ * Observes dblclicked on element event, provides dblclicked element model.
138
+ */
139
+ observeDblClickOnElement() {
140
+ return this.dblClickSubject.asObservable();
141
+ }
142
+ /**
143
+ * Observes rightclicked on element event, provides rightclicked element model.
144
+ */
145
+ observeRightClickOnElement() {
146
+ return this.rightClickSubject.asObservable();
147
+ }
148
+ /**
149
+ * Retrieves the pixel data at the specified coordinates.
150
+ *
151
+ * @private
152
+ * @param {number} x - The x-coordinate of the pixel.
153
+ * @param {number} y - The y-coordinate of the pixel.
154
+ * @returns {Uint8ClampedArray} - The pixel data at the specified coordinates.
155
+ */
156
+ getPixel(x, y) {
157
+ const dpr = window.devicePixelRatio;
158
+ // it's heavy operation, so use cached value if possible
159
+ if (this.prevAnimationFrameId !== animationFrameId) {
160
+ this.curImgData = this.ctx.getImageData(x * dpr, y * dpr, 1, 1).data;
161
+ this.prevAnimationFrameId = animationFrameId;
162
+ }
163
+ return this.curImgData;
164
+ }
165
+ /**
166
+ * Resolves ht model based on the provided point
167
+ * @param point - The point for which to resolve model
168
+ */
169
+ resolveModel(point) {
170
+ const data = this.getPixel(point.x, point.y);
171
+ const id = this.colorToId(data[0] * 65536 + data[1] * 256 + data[2]);
172
+ const idNumber = Number(id);
173
+ const [subscriberToHit] = sortSubscribers(this.hitTestSubscribers, idNumber);
174
+ const model = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.lookup(id);
175
+ return model;
176
+ }
177
+ /**
178
+ * Resolves cursor type based on the provided point
179
+ * @param point - The point for which to resolve cursor type
180
+ * @returns - The resolved cursor type, if any
181
+ */
182
+ resolveCursor(point) {
183
+ var _a;
184
+ // do not spend time on resolving cursor if there are no subscribers that need it
185
+ if (!this.hitTestSubscribers.some(s => s.resolveCursor !== undefined)) {
186
+ return undefined;
187
+ }
188
+ const data = this.getPixel(point.x, point.y);
189
+ const id = this.colorToId(data[0] * 65536 + data[1] * 256 + data[2]);
190
+ const idNumber = Number(id);
191
+ const [subscriberToHit] = sortSubscribers(this.hitTestSubscribers, idNumber);
192
+ const model = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.lookup(id);
193
+ return (_a = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.resolveCursor) === null || _a === void 0 ? void 0 : _a.call(subscriberToHit, point, model);
194
+ }
195
+ /**
196
+ * Private method that handles hit test events.
197
+ * @param {Point} point - The point where the event occurred.
198
+ * @param {HitTestEvents} event - The type of event that occurred.
199
+ * @returns {void}
200
+ */
201
+ eventHandler(point, event) {
202
+ var _a, _b, _c, _d, _e, _f, _g;
203
+ const data = this.getPixel(point.x, point.y);
204
+ const id = this.colorToId(data[0] * 65536 + data[1] * 256 + data[2]);
205
+ const idNumber = Number(id);
206
+ const [subscriberToHit, restSubs] = sortSubscribers(this.hitTestSubscribers, idNumber);
207
+ const model = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.lookup(id);
208
+ const hitTestEvent = {
209
+ point,
210
+ model,
211
+ };
212
+ switch (event) {
213
+ case 'mousedown':
214
+ model && ((_a = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(subscriberToHit, model, point));
215
+ restSubs.forEach(sub => sub.onMouseDown && sub.onMouseDown(null, point));
216
+ break;
217
+ case 'mouseup':
218
+ model && ((_b = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onMouseUp) === null || _b === void 0 ? void 0 : _b.call(subscriberToHit, model, point));
219
+ restSubs.forEach(sub => sub.onMouseUp && sub.onMouseUp(null, point));
220
+ break;
221
+ case 'hover':
222
+ model && ((_c = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onHover) === null || _c === void 0 ? void 0 : _c.call(subscriberToHit, model, point));
223
+ restSubs.forEach(sub => sub.onHover && sub.onHover(null, point));
224
+ this.hoverSubject.next(hitTestEvent);
225
+ break;
226
+ case 'touchstart':
227
+ model && ((_d = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onTouchStart) === null || _d === void 0 ? void 0 : _d.call(subscriberToHit, model, point));
228
+ restSubs.forEach(sub => sub.onTouchStart && sub.onTouchStart(null, point));
229
+ this.touchStartSubject.next(hitTestEvent);
230
+ break;
231
+ case 'dblclick':
232
+ model && ((_e = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onDblClick) === null || _e === void 0 ? void 0 : _e.call(subscriberToHit, model, point));
233
+ this.dblClickSubject.next(hitTestEvent);
234
+ break;
235
+ case 'contextmenu':
236
+ model && ((_f = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onRightClick) === null || _f === void 0 ? void 0 : _f.call(subscriberToHit, model, point));
237
+ this.rightClickSubject.next(hitTestEvent);
238
+ break;
239
+ case 'zoom':
240
+ model && ((_g = subscriberToHit === null || subscriberToHit === void 0 ? void 0 : subscriberToHit.onZoom) === null || _g === void 0 ? void 0 : _g.call(subscriberToHit, model, point));
241
+ restSubs.forEach(sub => sub.onZoom && sub.onZoom(null, point));
242
+ break;
243
+ default:
244
+ break;
245
+ }
246
+ }
247
+ }
248
+ const sortSubscribers = (subs, id) => {
249
+ let mainSubscriber = undefined;
250
+ const restSubs = [];
251
+ subs.forEach(sub => {
252
+ const [start, end] = sub.getIdRange();
253
+ if (id >= start && id <= end) {
254
+ mainSubscriber = sub;
255
+ }
256
+ else {
257
+ restSubs.push(sub);
258
+ }
259
+ });
260
+ return [mainSubscriber, restSubs];
261
+ };
@@ -18,7 +18,7 @@ import VisualCandle from './visual-candle';
18
18
  */
19
19
  export declare class MainCandleSeriesModel extends CandleSeriesModel {
20
20
  private readonly baseModel;
21
- constructor(baseModel: ChartBaseModel<'candle'>, extentComponent: YExtentComponent, id: number, eventBus: EventBus, scaleModel: ScaleModel, instrument: ChartInstrument, candlesTransformersByChartType: Partial<Record<DataSeriesType, VisualCandleCalculator>>, candleWidthByChartType: Partial<Record<DataSeriesType, CandleWidthCalculator>>, colors: CandleSeriesColors);
21
+ constructor(baseModel: ChartBaseModel<'candle'>, extentComponent: YExtentComponent, id: number, eventBus: EventBus, scale: ScaleModel, instrument: ChartInstrument, candlesTransformersByChartType: Partial<Record<DataSeriesType, VisualCandleCalculator>>, candleWidthByChartType: Partial<Record<DataSeriesType, CandleWidthCalculator>>, colors: CandleSeriesColors);
22
22
  set visualPoints(candles: VisualCandle[] | VisualCandle[][]);
23
23
  get visualPoints(): VisualCandle[];
24
24
  set dataPoints(candles: Candle[] | Candle[][]);
@@ -3,4 +3,32 @@
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{CandleSeriesModel as r}from"./candle-series.model";export class MainCandleSeriesModel extends r{constructor(e,s,a,t,i,n,o,l,d){super(s,a,t,i,n,o,l,d),this.baseModel=e}set visualPoints(e){super.visualPoints=e,this.baseModel.mainVisualPoints=super.visualPoints}get visualPoints(){return super.visualPoints}set dataPoints(e){super.dataPoints=e,this.baseModel.mainDataPoints=super.dataPoints}get dataPoints(){return super.dataPoints}recalculateMeanCandleWidth(e){super.recalculateMeanCandleWidth(e),this.baseModel.meanDataWidth=this.meanCandleWidth}}
6
+ import { CandleSeriesModel } from './candle-series.model';
7
+ /**
8
+ * This model represents main chart data series and is highly tied to chartBaseModel, @see ChartBaseModel
9
+ */
10
+ export class MainCandleSeriesModel extends CandleSeriesModel {
11
+ constructor(baseModel, extentComponent, id, eventBus, scale, instrument, candlesTransformersByChartType, candleWidthByChartType, colors) {
12
+ super(extentComponent, id, eventBus, scale, instrument, candlesTransformersByChartType, candleWidthByChartType, colors);
13
+ this.baseModel = baseModel;
14
+ }
15
+ set visualPoints(candles) {
16
+ super.visualPoints = candles;
17
+ // super.visualPoints will transform 2D array if necessary to 1D array
18
+ this.baseModel.mainVisualPoints = super.visualPoints;
19
+ }
20
+ get visualPoints() {
21
+ return super.visualPoints;
22
+ }
23
+ set dataPoints(candles) {
24
+ super.dataPoints = candles;
25
+ this.baseModel.mainDataPoints = super.dataPoints;
26
+ }
27
+ get dataPoints() {
28
+ return super.dataPoints;
29
+ }
30
+ recalculateMeanCandleWidth(visualCandles) {
31
+ super.recalculateMeanCandleWidth(visualCandles);
32
+ this.baseModel.meanDataWidth = this.meanCandleWidth;
33
+ }
34
+ }
@@ -40,6 +40,7 @@ export declare class ScaleModel extends ViewportModel {
40
40
  getBounds: BoundsProvider;
41
41
  private canvasAnimation;
42
42
  scaleInversedSubject: Subject<boolean>;
43
+ beforeStartAnimationSubject: Subject<void>;
43
44
  history: ScaleHistoryItem[];
44
45
  autoScaleModel: AutoScaleViewportSubModel;
45
46
  zoomXYRatio: ZoomXToZoomYRatio;
@@ -49,7 +50,7 @@ export declare class ScaleModel extends ViewportModel {
49
50
  constructor(config: FullChartConfig, getBounds: BoundsProvider, canvasAnimation: CanvasAnimation);
50
51
  /**
51
52
  * The method adds a new "constraint" to the existing list of x-axis constraints for charting.
52
- * The "constrait" is expected to be an object containing information about the constraints, such as the minimum and maximum values for the x-axis.
53
+ * The "constraint" is expected to be an object containing information about the constraints, such as the minimum and maximum values for the x-axis.
53
54
  * @param constraint
54
55
  */
55
56
  addXConstraint(constraint: Constraints): void;
@@ -77,7 +78,7 @@ export declare class ScaleModel extends ViewportModel {
77
78
  * @param zoomSensitivity - The sensitivity of the zoom. Default value is taken from the configuration object.
78
79
  */
79
80
  zoomXToEnd(zoomIn: boolean, zoomSensitivity?: number): void;
80
- private haltAnimation;
81
+ haltAnimation(): void;
81
82
  private zoomXTo;
82
83
  /**
83
84
  * Moves the viewport to exactly xStart..xEnd place.
@@ -3,4 +3,319 @@
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 c}from"rxjs";import{startViewportModelAnimation as l}from"../animation/viewport-model-animation";import{cloneUnsafe as u}from"../utils/object.utils";import{AutoScaleViewportSubModel as d}from"./scaling/auto-scale.model";import{zoomConstraint as m}from"./scaling/constrait.functions";import{lockedYEndViewportCalculator as a,ratioFromZoomXY as p}from"./scaling/lock-ratio.model";import{moveXStart as f,moveYStart as S}from"./scaling/move-chart.functions";import{ViewportModel as g,compareStates as x}from"./scaling/viewport.model";import{zoomXToEndViewportCalculator as A,zoomXToPercentViewportCalculator as y}from"./scaling/x-zooming.functions";export const getDefaultHighLowWithIndex=()=>({high:Number.NEGATIVE_INFINITY,low:Number.POSITIVE_INFINITY,highIdx:0,lowIdx:0});export class ScaleModel extends g{constructor(t,s,e){super(),this.config=t,this.getBounds=s,this.canvasAnimation=e,this.scaleInversedSubject=new c,this.history=[],this.zoomXYRatio=0,this.xConstraints=[],this.scalePostProcessor=(o,i)=>this.xConstraints.reduce((n,h)=>h(o,n),i),this.state=u(t.scale),this.autoScaleModel=new d(this),this.offsets=this.config.components.offsets,this.addXConstraint((o,i)=>m(o,i,this.config.components.chart,this.getBounds))}addXConstraint(t){this.xConstraints=[...this.xConstraints,t]}updateOffsets(t){this.offsets=Object.assign(Object.assign({},this.offsets),t),this.doAutoScale(!0)}getOffsets(){return this.offsets}zoomXToPercent(t,s,e=!1,o=this.config.scale.zoomSensitivity){this.config.components.yAxis.type==="percent"&&this.haltAnimation();const i=this.export();y(this,i,t,o,s),this.zoomXTo(i,e)}zoomXToEnd(t,s=this.config.scale.zoomSensitivity){this.config.components.yAxis.type==="percent"&&this.haltAnimation();const e=this.export();A(this,e,s,t),this.zoomXTo(e)}haltAnimation(){var t;!((t=this.currentAnimation)===null||t===void 0)&&t.animationInProgress&&(this.currentAnimation.finishAnimation(),this.doAutoScale())}zoomXTo(t,s){const e=Object.assign({},t),o=this.scalePostProcessor(e,t);this.state.lockPriceToBarRatio&&a(o,this.zoomXYRatio),this.state.auto&&this.autoScaleModel.setAutoAndRecalculateState(o,!0),s?this.apply(o):l(this.canvasAnimation,this,o)}setXScale(t,s){const e=this.export();super.setXScale(t,s,!1);const o=this.export(),i=this.scalePostProcessor(e,o);this.state.lockPriceToBarRatio&&a(i,this.zoomXYRatio),this.state.auto&&this.autoScaleModel.setAutoAndRecalculateState(i,!0),this.apply(i)}moveXStart(t){const s=this.export(),e=Object.assign({},s);this.haltAnimation(),f(s,t);const o=this.scalePostProcessor(e,s);this.state.auto&&this.autoScaleModel.setAutoAndRecalculateState(o,!0),this.apply(o)}moveYStart(t){if(this.haltAnimation(),!this.state.auto){const s=this.export();S(s,t),this.apply(s)}}doAutoScale(t=!1){if(!this.isViewportAnimationInProgress()&&this.state.auto||t){const s=this.export();this.autoScaleModel.setAutoAndRecalculateState(s,!0),x(s,this.export())||this.apply(s)}}isViewportAnimationInProgress(){const t=this.currentAnimation;return t==null?void 0:t.animationInProgress}pushToHistory(t){this.history.push(t)}popFromHistory(){return this.history.pop()}clearHistory(){this.history=[]}isDefaultXBounds(){return this.xStart===0&&this.xEnd===0}isDefaultYBounds(){return this.yStart===0&&this.yEnd===0}isScaleReady(){return!this.isDefaultXBounds()&&!this.isDefaultYBounds()}autoScale(t=!0){this.config.components.yAxis.type==="percent"?this.state.auto=!0:this.state.auto=t,t&&(this.clearHistory(),this.doAutoScale())}setLockPriceToBarRatio(t=!1){const{type:s}=this.config.components.yAxis;if(s==="percent"||s==="logarithmic"){this.state.lockPriceToBarRatio=!1;return}t&&this.recalculateZoomXYRatio(),this.state.lockPriceToBarRatio=t}recalculateZoomXYRatio(){this.zoomXYRatio=p(this.zoomX,this.zoomY)}}export class SyncedByXScaleModel extends ScaleModel{constructor(t,s,e,o){super(s,e,o),this.delegate=t,this.config=s,this.getBounds=e}doActivate(){this.addRxSubscription(this.delegate.xChanged.subscribe(()=>this.doAutoScale(this.state.auto)))}get xStart(){return this.delegate.xStart}set xStart(t){this.delegate.xStart=t}get xEnd(){return this.delegate.xEnd}set xEnd(t){this.delegate.xEnd=t}get zoomX(){return this.delegate.zoomX}set zoomX(t){this.delegate.zoomX=t}observeXChanged(){return this.delegate.xChanged}fireChanged(){this.delegate.changed.next(),this.changed.next()}}
6
+ import { Subject } from 'rxjs';
7
+ import { startViewportModelAnimation } from '../animation/viewport-model-animation';
8
+ import { cloneUnsafe } from '../utils/object.utils';
9
+ import { AutoScaleViewportSubModel } from './scaling/auto-scale.model';
10
+ import { zoomConstraint } from './scaling/constrait.functions';
11
+ import { lockedYEndViewportCalculator, ratioFromZoomXY } from './scaling/lock-ratio.model';
12
+ import { moveXStart, moveYStart } from './scaling/move-chart.functions';
13
+ import { ViewportModel, compareStates } from './scaling/viewport.model';
14
+ import { zoomXToEndViewportCalculator, zoomXToPercentViewportCalculator } from './scaling/x-zooming.functions';
15
+ export const getDefaultHighLowWithIndex = () => ({
16
+ high: Number.NEGATIVE_INFINITY,
17
+ low: Number.POSITIVE_INFINITY,
18
+ highIdx: 0,
19
+ lowIdx: 0,
20
+ });
21
+ /**
22
+ * The ScaleModel class represents the state of a chart's scale, including the current viewport, zoom level, and auto-scaling settings.
23
+ * It extends the ViewportModel class, which provides the underlying implementation for handling viewports and zoom levels.
24
+ * Controls current visible CHART viewport.
25
+ * Has additional logic:
26
+ * - auto-scale
27
+ * - locked scale
28
+ * - zooming functions
29
+ * - history
30
+ */
31
+ export class ScaleModel extends ViewportModel {
32
+ constructor(config, getBounds, canvasAnimation) {
33
+ super();
34
+ this.config = config;
35
+ this.getBounds = getBounds;
36
+ this.canvasAnimation = canvasAnimation;
37
+ this.scaleInversedSubject = new Subject();
38
+ // y-axis component needs this subject in order to halt prev animation if axis type is percent
39
+ this.beforeStartAnimationSubject = new Subject();
40
+ // TODO rework, make a new history based on units
41
+ this.history = [];
42
+ this.zoomXYRatio = 0;
43
+ this.xConstraints = [];
44
+ this.scalePostProcessor = (initialState, state) => {
45
+ // for now <s>reduceRight<s/> reduce bcs ChartModel#getZoomConstrait should be invoked first
46
+ // if we will need more complex order handling -> add some managing
47
+ return this.xConstraints.reduce((acc, cur) => cur(initialState, acc), state);
48
+ };
49
+ this.state = cloneUnsafe(config.scale);
50
+ this.autoScaleModel = new AutoScaleViewportSubModel(this);
51
+ this.offsets = this.config.components.offsets;
52
+ this.addXConstraint((initialState, state) => zoomConstraint(initialState, state, this.config.components.chart, this.getBounds));
53
+ }
54
+ /**
55
+ * The method adds a new "constraint" to the existing list of x-axis constraints for charting.
56
+ * The "constraint" is expected to be an object containing information about the constraints, such as the minimum and maximum values for the x-axis.
57
+ * @param constraint
58
+ */
59
+ addXConstraint(constraint) {
60
+ this.xConstraints = [...this.xConstraints, constraint];
61
+ }
62
+ /**
63
+ * The method updates the offsets for the scale model based on the provided "offsets" object.
64
+ * Note that the method modifies the offsets and triggers an autoscale
65
+ * @param offsets
66
+ */
67
+ updateOffsets(offsets) {
68
+ this.offsets = Object.assign(Object.assign({}, this.offsets), offsets);
69
+ this.doAutoScale(true);
70
+ }
71
+ /**
72
+ * @returns current offsets
73
+ */
74
+ getOffsets() {
75
+ return this.offsets;
76
+ }
77
+ /**
78
+ * Zooms the X axis of the chart to a specified percentage of the viewport.
79
+ * @param viewportPercent The percentage of the viewport width to zoom to.
80
+ * @param zoomIn Whether to zoom in or out.
81
+ * @param forceNoAnimation Whether to skip animation.
82
+ * @param zoomSensitivity The sensitivity of the zoom.
83
+ */
84
+ zoomXToPercent(viewportPercent, zoomIn, forceNoAnimation = false, zoomSensitivity = this.config.scale.zoomSensitivity) {
85
+ this.beforeStartAnimationSubject.next();
86
+ const state = this.export();
87
+ zoomXToPercentViewportCalculator(this, state, viewportPercent, zoomSensitivity, zoomIn);
88
+ this.zoomXTo(state, forceNoAnimation);
89
+ }
90
+ /**
91
+ * Zooms the X axis of the chart relativly to the end of the data range.
92
+ * @param zoomIn - If true, the chart will be zoomed in. If false, the chart will be zoomed out.
93
+ * @param zoomSensitivity - The sensitivity of the zoom. Default value is taken from the configuration object.
94
+ */
95
+ zoomXToEnd(zoomIn, zoomSensitivity = this.config.scale.zoomSensitivity) {
96
+ this.beforeStartAnimationSubject.next();
97
+ const state = this.export();
98
+ zoomXToEndViewportCalculator(this, state, zoomSensitivity, zoomIn);
99
+ this.zoomXTo(state);
100
+ }
101
+ haltAnimation() {
102
+ var _a;
103
+ if ((_a = this.currentAnimation) === null || _a === void 0 ? void 0 : _a.animationInProgress) {
104
+ this.currentAnimation.finishAnimation();
105
+ this.doAutoScale();
106
+ }
107
+ }
108
+ zoomXTo(state, forceNoAnimation) {
109
+ const initialStateCopy = Object.assign({}, state);
110
+ const constrainedState = this.scalePostProcessor(initialStateCopy, state);
111
+ if (this.state.lockPriceToBarRatio) {
112
+ lockedYEndViewportCalculator(constrainedState, this.zoomXYRatio);
113
+ }
114
+ if (this.state.auto) {
115
+ this.autoScaleModel.doAutoYScale(constrainedState);
116
+ }
117
+ if (forceNoAnimation) {
118
+ this.apply(constrainedState);
119
+ }
120
+ else {
121
+ startViewportModelAnimation(this.canvasAnimation, this, constrainedState);
122
+ }
123
+ }
124
+ /**
125
+ * Moves the viewport to exactly xStart..xEnd place.
126
+ * (you need to fire DRAW event after this)
127
+ * @param xStart - viewport start in units
128
+ * @param xEnd - viewport end in units
129
+ * @param fireChanged
130
+ * @param forceNoAutoScale - force NOT apply auto-scaling (for lazy loading)
131
+ */
132
+ setXScale(xStart, xEnd) {
133
+ const initialState = this.export();
134
+ super.setXScale(xStart, xEnd, false);
135
+ const state = this.export();
136
+ const constrainedState = this.scalePostProcessor(initialState, state);
137
+ if (this.state.lockPriceToBarRatio) {
138
+ lockedYEndViewportCalculator(constrainedState, this.zoomXYRatio);
139
+ }
140
+ if (this.state.auto) {
141
+ this.autoScaleModel.doAutoYScale(constrainedState);
142
+ }
143
+ this.apply(constrainedState);
144
+ }
145
+ /**
146
+ * Moves both xStart and xEnd without changing the viewport width (zoom).
147
+ * WILL CHANGE the Y axis if scale.auto=true.
148
+ * @param xStart - starting point in units
149
+ */
150
+ moveXStart(xStart) {
151
+ const state = this.export();
152
+ const initialStateCopy = Object.assign({}, state);
153
+ // always stop the animations
154
+ this.haltAnimation();
155
+ moveXStart(state, xStart);
156
+ // there we need only candles constraint
157
+ const constrainedState = this.scalePostProcessor(initialStateCopy, state);
158
+ if (this.state.auto) {
159
+ this.autoScaleModel.doAutoYScale(constrainedState);
160
+ }
161
+ this.apply(constrainedState);
162
+ }
163
+ /**
164
+ * Moves both yStart and yEnd without changing the viewport height (zoom).
165
+ * Will not move viewport if scale.auto=true
166
+ * @param yStart - starting point in units
167
+ */
168
+ moveYStart(yStart) {
169
+ this.haltAnimation();
170
+ if (this.state.auto) {
171
+ return;
172
+ }
173
+ else {
174
+ const state = this.export();
175
+ moveYStart(state, yStart);
176
+ this.apply(state);
177
+ }
178
+ }
179
+ /**
180
+ * Automatically scales the chart to fit the data range.
181
+ * @param forceApply - If true, the chart will be forcefully auto-scaled even if animation is in progress.
182
+ */
183
+ doAutoScale(forceApply = false) {
184
+ // dont auto-scale if animation, otherwise - forced or config
185
+ if ((!this.isViewportAnimationInProgress() && this.state.auto) || forceApply) {
186
+ const state = this.export();
187
+ this.autoScaleModel.doAutoYScale(state);
188
+ if (!compareStates(state, this.export())) {
189
+ this.apply(state);
190
+ }
191
+ }
192
+ }
193
+ /**
194
+ * Checks if viewport animation is currently in progress.
195
+ * @returns returns true if viewport animation is in progress, false otherwise.
196
+ */
197
+ isViewportAnimationInProgress() {
198
+ const animation = this.currentAnimation;
199
+ return animation === null || animation === void 0 ? void 0 : animation.animationInProgress;
200
+ }
201
+ /**
202
+ * Adds an item to the scale history.
203
+ * @param item - The item to add to the history.
204
+ */
205
+ pushToHistory(item) {
206
+ this.history.push(item);
207
+ }
208
+ /**
209
+ * Removes the most recent item from the scale history and returns it.
210
+ * @returns - The most recent item from the history, or undefined if the history is empty.
211
+ */
212
+ popFromHistory() {
213
+ return this.history.pop();
214
+ }
215
+ /**
216
+ * Clears the scale history.
217
+ */
218
+ clearHistory() {
219
+ this.history = [];
220
+ }
221
+ /**
222
+ * Checks if the X axis bounds are the default values.
223
+ * @returns if false - it means there are candles and it's possible to do scaling and add drawings
224
+ */
225
+ isDefaultXBounds() {
226
+ return this.xStart === 0 && this.xEnd === 0;
227
+ }
228
+ /**
229
+ * Checks if the Y axis bounds are the default values.
230
+ * @returns if false - it means there are candles and it's possible to do scaling and add drawings
231
+ */
232
+ isDefaultYBounds() {
233
+ return this.yStart === 0 && this.yEnd === 0;
234
+ }
235
+ /**
236
+ * Checks if the scale is ready to be used.
237
+ * @returns - Returns true if the scale is ready, false otherwise.
238
+ */
239
+ isScaleReady() {
240
+ return !this.isDefaultXBounds() && !this.isDefaultYBounds();
241
+ }
242
+ /**
243
+ * Enables or disables auto-scaling of the chart.
244
+ * @param auto - If true, the chart will be automatically scaled. If false, auto-scaling will be disabled.
245
+ */
246
+ autoScale(auto = true) {
247
+ // TODO rework, make this a separate feature toggle, describe in docs; this should be a business-logic level
248
+ if (this.config.components.yAxis.type === 'percent') {
249
+ this.state.auto = true;
250
+ }
251
+ else {
252
+ this.state.auto = auto;
253
+ }
254
+ if (auto) {
255
+ this.clearHistory();
256
+ this.doAutoScale();
257
+ }
258
+ }
259
+ /**
260
+ * Sets whether the price-to-bar ratio should be locked or not.
261
+ * @param value - If true, the price-to-bar ratio will be locked. If false, it will not be locked.
262
+ */
263
+ setLockPriceToBarRatio(value = false) {
264
+ const { type } = this.config.components.yAxis;
265
+ // TODO rework, why such logic? same as above, if we have business-logic like this one => make it separate code
266
+ if (type === 'percent' || type === 'logarithmic') {
267
+ this.state.lockPriceToBarRatio = false;
268
+ return;
269
+ }
270
+ if (value) {
271
+ this.recalculateZoomXYRatio();
272
+ }
273
+ this.state.lockPriceToBarRatio = value;
274
+ }
275
+ /**
276
+ * Recalculates the zoom X/Y ratio based on the current zoom levels.
277
+ */
278
+ recalculateZoomXYRatio() {
279
+ this.zoomXYRatio = ratioFromZoomXY(this.zoomX, this.zoomY);
280
+ }
281
+ }
282
+ /**
283
+ * The SyncedByXScaleModel class extends the ScaleModel class and adds support for synchronization with other ScaleModel instance, so both instances maintain the same X-axis bounds.
284
+ * This is useful for scenarios where multiple charts need to display the same X-axis data, but with different Y-axis scales.
285
+ */
286
+ export class SyncedByXScaleModel extends ScaleModel {
287
+ constructor(delegate, config, getBounds, canvasAnimation) {
288
+ super(config, getBounds, canvasAnimation);
289
+ this.delegate = delegate;
290
+ this.config = config;
291
+ this.getBounds = getBounds;
292
+ }
293
+ doActivate() {
294
+ this.addRxSubscription(this.delegate.xChanged.subscribe(() => this.doAutoScale(this.state.auto)));
295
+ }
296
+ get xStart() {
297
+ return this.delegate.xStart;
298
+ }
299
+ set xStart(value) {
300
+ this.delegate.xStart = value;
301
+ }
302
+ get xEnd() {
303
+ return this.delegate.xEnd;
304
+ }
305
+ set xEnd(value) {
306
+ this.delegate.xEnd = value;
307
+ }
308
+ get zoomX() {
309
+ return this.delegate.zoomX;
310
+ }
311
+ set zoomX(value) {
312
+ this.delegate.zoomX = value;
313
+ }
314
+ observeXChanged() {
315
+ return this.delegate.xChanged;
316
+ }
317
+ fireChanged() {
318
+ this.delegate.changed.next();
319
+ this.changed.next();
320
+ }
321
+ }