@devexperts/dxcharts-lite 2.7.16 → 2.7.18

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 (50) hide show
  1. package/dist/chart/animation/canvas-animation.d.ts +1 -0
  2. package/dist/chart/animation/canvas-animation.js +2 -1
  3. package/dist/chart/animation/viewport-model-animation.d.ts +4 -1
  4. package/dist/chart/animation/viewport-model-animation.js +21 -3
  5. package/dist/chart/bootstrap.js +17 -5
  6. package/dist/chart/chart.config.js +1 -1
  7. package/dist/chart/components/chart/chart-area-pan.handler.d.ts +16 -16
  8. package/dist/chart/components/chart/chart-area-pan.handler.js +8 -2
  9. package/dist/chart/components/chart/chart.component.js +2 -0
  10. package/dist/chart/components/chart/chart.model.d.ts +11 -0
  11. package/dist/chart/components/chart/chart.model.js +20 -0
  12. package/dist/chart/components/cross_tool/cross-tool.component.d.ts +3 -1
  13. package/dist/chart/components/cross_tool/cross-tool.component.js +3 -2
  14. package/dist/chart/components/cross_tool/cross-tool.model.d.ts +6 -3
  15. package/dist/chart/components/cross_tool/cross-tool.model.js +9 -5
  16. package/dist/chart/components/grid/grid.component.d.ts +1 -1
  17. package/dist/chart/components/grid/grid.component.js +2 -2
  18. package/dist/chart/components/grid/grid.drawer.d.ts +2 -1
  19. package/dist/chart/components/grid/grid.drawer.js +3 -2
  20. package/dist/chart/components/pan/chart-pan.component.js +17 -1
  21. package/dist/chart/components/pane/pane.component.js +3 -1
  22. package/dist/chart/drawers/data-series-drawers/trend-points.drawer.d.ts +12 -0
  23. package/dist/chart/drawers/data-series-drawers/trend-points.drawer.js +70 -0
  24. package/dist/chart/drawers/drawing-manager.js +0 -1
  25. package/dist/chart/inputhandlers/chart-resize.handler.d.ts +5 -0
  26. package/dist/chart/inputhandlers/chart-resize.handler.js +9 -1
  27. package/dist/chart/inputlisteners/canvas-input-listener.component.d.ts +28 -0
  28. package/dist/chart/inputlisteners/canvas-input-listener.component.js +104 -7
  29. package/dist/chart/model/data-series.config.d.ts +1 -1
  30. package/dist/chart/model/hit-test-canvas.model.d.ts +15 -13
  31. package/dist/chart/model/hit-test-canvas.model.js +2 -2
  32. package/dist/chart/model/scale.model.d.ts +5 -0
  33. package/dist/chart/model/scale.model.js +73 -7
  34. package/dist/chart/utils/device/touchpad.utils.d.ts +1 -0
  35. package/dist/chart/utils/device/touchpad.utils.js +1 -1
  36. package/dist/chart/utils/math.utils.js +1 -1
  37. package/dist/chart/utils/performance/queue-microtask.utils.d.ts +5 -0
  38. package/dist/chart/utils/performance/queue-microtask.utils.js +12 -0
  39. package/dist/chart/utils/performance/request-animation-frame-throttle.utils.d.ts +1 -0
  40. package/dist/chart/utils/performance/request-animation-frame-throttle.utils.js +3 -0
  41. package/dist/chart/utils/performance/safari/components/animations/safari-canvas-animation.d.ts +77 -0
  42. package/dist/chart/utils/performance/safari/components/animations/safari-canvas-animation.js +137 -0
  43. package/dist/chart/utils/performance/safari/components/chart-area-pan.handler/safari-chart-area-pan.handler.d.ts +54 -0
  44. package/dist/chart/utils/performance/safari/components/chart-area-pan.handler/safari-chart-area-pan.handler.js +180 -0
  45. package/dist/chart/utils/performance/safari/safari-performance.model.d.ts +32 -0
  46. package/dist/chart/utils/performance/safari/safari-performance.model.js +31 -0
  47. package/dist/chart/utils/performance/safari/safari-performance.utils.d.ts +18 -0
  48. package/dist/chart/utils/performance/safari/safari-performance.utils.js +34 -0
  49. package/dist/dxchart.min.js +4 -4
  50. package/package.json +2 -2
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ "use strict";
7
+ // Polyfill for queueMicrotask in jsdom
8
+ if (typeof window.queueMicrotask === 'undefined') {
9
+ window.queueMicrotask = (callback) => {
10
+ Promise.resolve().then(callback);
11
+ };
12
+ }
@@ -6,6 +6,7 @@
6
6
  export declare let animationFrameId: number;
7
7
  export declare const animationFrameThrottled: (name: string, action: () => void) => void;
8
8
  export declare const cancelThrottledAnimationFrame: (name: string) => void;
9
+ export declare const cancelThrottledAnimationFramePrior: (name: string) => void;
9
10
  /**
10
11
  * Prior actions will be called before regular actions
11
12
  * An example of regular action - draw event
@@ -31,6 +31,9 @@ export const animationFrameThrottled = (name, action) => {
31
31
  export const cancelThrottledAnimationFrame = (name) => {
32
32
  actions.delete(name);
33
33
  };
34
+ export const cancelThrottledAnimationFramePrior = (name) => {
35
+ priorActions.delete(name);
36
+ };
34
37
  /**
35
38
  * Prior actions will be called before regular actions
36
39
  * An example of regular action - draw event
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import { BehaviorSubject } from 'rxjs';
7
+ import EventBus from '../../../../../events/event-bus';
8
+ import { ViewportModel } from '../../../../../model/scaling/viewport.model';
9
+ import { ViewportMovementAnimation, ViewportMovementAnimationConfig } from '../../../../../animation/types/viewport-movement-animation';
10
+ import { AnimationConfig, CanvasAnimation } from '../../../../../animation/canvas-animation';
11
+ import { ColorAlphaAnimation, ColorAlphaAnimationConfig } from '../../../../../animation/types/color-alpha-animation';
12
+ import { ColorTransitionAnimation, ColorTransitionAnimationConfig } from '../../../../../animation/types/color-transition-animation';
13
+ export declare class SafariCanvasAnimation extends CanvasAnimation {
14
+ animations: Record<string, any>;
15
+ animFrameId: string;
16
+ animationInProgressSubject: BehaviorSubject<boolean>;
17
+ private microtaskQueued;
18
+ constructor(eventBus: EventBus);
19
+ /**
20
+ * Starts a viewport movement animation with the given configuration and adds it to the list of animations.
21
+ * @param {ViewportModel} viewportModel - The viewport model to animate.
22
+ * @param {ViewportMovementAnimationConfig} config - The configuration for the animation.
23
+ * @param {string} [uniqueAnimationId=VIEWPORT_ANIMATION_ID] - The unique ID for the animation.
24
+ * @param {Function} [onTickFunction] - The function to be called on each tick of the animation.
25
+ * @returns {ViewportMovementAnimation} The container for the created animation.
26
+ */
27
+ startViewportMovementAnimation(viewportModel: ViewportModel, config: ViewportMovementAnimationConfig, uniqueAnimationId: string | undefined, onTickFunction: {
28
+ (): boolean;
29
+ (): void;
30
+ }): ViewportMovementAnimation;
31
+ /**
32
+ * Starts a color alpha animation with the given configuration and adds it to the list of animations.
33
+ * @param {string} uniqueAnimationId - A unique identifier for the animation.
34
+ * @param {Array<ColorAlphaAnimationConfig>} colorConfigs - An array of color alpha animation configurations.
35
+ * @param {() => void} [onTickFunction] - A function to be called on each animation tick.
36
+ * @param {Partial<ACAnimationConfig>} [animationConfig] - An optional configuration for the animation.
37
+ * @returns {ColorAlphaAnimation} - The created animation container.
38
+ */
39
+ startColorAlphaAnimation(uniqueAnimationId: string, colorConfigs: Array<ColorAlphaAnimationConfig>, onTickFunction?: (() => void) | undefined, animationConfig?: AnimationConfig): ColorAlphaAnimation;
40
+ /**
41
+ * Starts a color transition animation with the given configurations and duration.
42
+ * @param {string} uniqueAnimationId - A unique identifier for the animation.
43
+ * @param {Array<ColorTransitionAnimationConfig>} colorConfigs - An array of color transition configurations.
44
+ * @param {number} [duration=DEFAULT_ANIMATION_TIME] - The duration of the animation in milliseconds.
45
+ * @param {Function} [onTickFunction] - A function to be called on each tick of the animation.
46
+ * @returns {ColorTransitionAnimation} - The created animation container.
47
+ */
48
+ startColorTransitionAnimation(uniqueAnimationId: string, colorConfigs: Array<ColorTransitionAnimationConfig>, duration?: number, onTickFunction?: () => void): ColorTransitionAnimation;
49
+ /**
50
+ * This function takes an id as a string and returns an animation container object of type T. It retrieves the animation container object from the animations object using the provided id. The @ts-ignore comment is used to ignore any TypeScript errors that may occur due to the dynamic nature of the function.
51
+ */
52
+ getAnimation(id: string | number): any;
53
+ /**
54
+ * Returns a ColorAlphaAnimation object for the given animation ID.
55
+ *
56
+ * @param {string} id - The ID of the animation to retrieve.
57
+ * @returns {ColorAlphaAnimation} - The ColorAlphaAnimation object for the given ID.
58
+ */
59
+ getColorAlphaAnimation(id: string): any;
60
+ /**
61
+ * Returns a ColorTransitionAnimation object for the given id.
62
+ * @param {string} id - The id of the animation to retrieve.
63
+ * @returns {ColorTransitionAnimation} - The ColorTransitionAnimation object for the given id.
64
+ */
65
+ getColorTransitionAnimation(id: string): any;
66
+ /**
67
+ * Stops the animation with the given ID.
68
+ * @param {string} id - The ID of the animation to be stopped.
69
+ * @returns {void}
70
+ */
71
+ forceStopAnimation(id: string): void;
72
+ /**
73
+ * This is a private method that iterates through all the animations in the container and calls their tick method. If any animation is still in progress, it sets the allCompleted flag to false. If all animations are completed, it stops the interval. If not, it fires the draw event.
74
+ */
75
+ tick(): void;
76
+ stopInterval(): void;
77
+ }
@@ -0,0 +1,137 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import { BehaviorSubject } from 'rxjs';
7
+ import { cancelThrottledAnimationFramePrior } from '../../../../../utils/performance/request-animation-frame-throttle.utils';
8
+ import { ViewportMovementAnimation, } from '../../../../../animation/types/viewport-movement-animation';
9
+ import { CanvasAnimation, DEFAULT_ANIMATION_TIME_MS, VIEWPORT_ANIMATION_ID, } from '../../../../../animation/canvas-animation';
10
+ import { ColorAlphaAnimation } from '../../../../../animation/types/color-alpha-animation';
11
+ import { ColorTransitionAnimation, } from '../../../../../animation/types/color-transition-animation';
12
+ export class SafariCanvasAnimation extends CanvasAnimation {
13
+ constructor(eventBus) {
14
+ super(eventBus);
15
+ this.animations = {};
16
+ this.animFrameId = 'animation';
17
+ this.animationInProgressSubject = new BehaviorSubject(false);
18
+ this.microtaskQueued = false; // Flag to prevent accumulation of queueMicrotask calls
19
+ }
20
+ /**
21
+ * Starts a viewport movement animation with the given configuration and adds it to the list of animations.
22
+ * @param {ViewportModel} viewportModel - The viewport model to animate.
23
+ * @param {ViewportMovementAnimationConfig} config - The configuration for the animation.
24
+ * @param {string} [uniqueAnimationId=VIEWPORT_ANIMATION_ID] - The unique ID for the animation.
25
+ * @param {Function} [onTickFunction] - The function to be called on each tick of the animation.
26
+ * @returns {ViewportMovementAnimation} The container for the created animation.
27
+ */
28
+ startViewportMovementAnimation(viewportModel, config, uniqueAnimationId = VIEWPORT_ANIMATION_ID, onTickFunction) {
29
+ const animation = new ViewportMovementAnimation(viewportModel, config, onTickFunction);
30
+ this.animations[uniqueAnimationId] = animation;
31
+ this.processAnimation();
32
+ return animation;
33
+ }
34
+ /**
35
+ * Starts a color alpha animation with the given configuration and adds it to the list of animations.
36
+ * @param {string} uniqueAnimationId - A unique identifier for the animation.
37
+ * @param {Array<ColorAlphaAnimationConfig>} colorConfigs - An array of color alpha animation configurations.
38
+ * @param {() => void} [onTickFunction] - A function to be called on each animation tick.
39
+ * @param {Partial<ACAnimationConfig>} [animationConfig] - An optional configuration for the animation.
40
+ * @returns {ColorAlphaAnimation} - The created animation container.
41
+ */
42
+ startColorAlphaAnimation(uniqueAnimationId, colorConfigs, onTickFunction, animationConfig) {
43
+ const animation = new ColorAlphaAnimation(Object.assign(Object.assign({}, animationConfig), { duration: (animationConfig && animationConfig.duration) || DEFAULT_ANIMATION_TIME_MS }), colorConfigs, onTickFunction);
44
+ this.animations[uniqueAnimationId] = animation;
45
+ this.processAnimation();
46
+ return animation;
47
+ }
48
+ /**
49
+ * Starts a color transition animation with the given configurations and duration.
50
+ * @param {string} uniqueAnimationId - A unique identifier for the animation.
51
+ * @param {Array<ColorTransitionAnimationConfig>} colorConfigs - An array of color transition configurations.
52
+ * @param {number} [duration=DEFAULT_ANIMATION_TIME] - The duration of the animation in milliseconds.
53
+ * @param {Function} [onTickFunction] - A function to be called on each tick of the animation.
54
+ * @returns {ColorTransitionAnimation} - The created animation container.
55
+ */
56
+ startColorTransitionAnimation(uniqueAnimationId, colorConfigs, duration = DEFAULT_ANIMATION_TIME_MS, onTickFunction) {
57
+ const animation = new ColorTransitionAnimation({ duration }, colorConfigs, onTickFunction);
58
+ this.animations[uniqueAnimationId] = animation;
59
+ this.processAnimation();
60
+ return animation;
61
+ }
62
+ /**
63
+ * This function takes an id as a string and returns an animation container object of type T. It retrieves the animation container object from the animations object using the provided id. The @ts-ignore comment is used to ignore any TypeScript errors that may occur due to the dynamic nature of the function.
64
+ */
65
+ getAnimation(id) {
66
+ // @ts-ignore
67
+ return this.animations[id];
68
+ }
69
+ /**
70
+ * Returns a ColorAlphaAnimation object for the given animation ID.
71
+ *
72
+ * @param {string} id - The ID of the animation to retrieve.
73
+ * @returns {ColorAlphaAnimation} - The ColorAlphaAnimation object for the given ID.
74
+ */
75
+ getColorAlphaAnimation(id) {
76
+ return this.getAnimation(id);
77
+ }
78
+ /**
79
+ * Returns a ColorTransitionAnimation object for the given id.
80
+ * @param {string} id - The id of the animation to retrieve.
81
+ * @returns {ColorTransitionAnimation} - The ColorTransitionAnimation object for the given id.
82
+ */
83
+ getColorTransitionAnimation(id) {
84
+ return this.getAnimation(id);
85
+ }
86
+ /**
87
+ * Stops the animation with the given ID.
88
+ * @param {string} id - The ID of the animation to be stopped.
89
+ * @returns {void}
90
+ */
91
+ forceStopAnimation(id) {
92
+ const animation = this.animations[id];
93
+ if (animation) {
94
+ animation.animationInProgress = false;
95
+ animation.animationStartTime = 0;
96
+ // CRITICAL: Completely remove the animation to prevent it from being processed in tick()
97
+ delete this.animations[id];
98
+ }
99
+ // Stop the animation loop if no animations are running
100
+ if (Object.keys(this.animations).length === 0) {
101
+ this.stopInterval();
102
+ }
103
+ }
104
+ /**
105
+ * This is a private method that iterates through all the animations in the container and calls their tick method. If any animation is still in progress, it sets the allCompleted flag to false. If all animations are completed, it stops the interval. If not, it fires the draw event.
106
+ */
107
+ tick() {
108
+ let allCompleted = true;
109
+ for (const i of Object.keys(this.animations)) {
110
+ const animation = this.animations[i];
111
+ animation.tick();
112
+ if (animation.animationInProgress) {
113
+ allCompleted = false;
114
+ }
115
+ }
116
+ this.animationInProgressSubject.next(!allCompleted);
117
+ if (!allCompleted) {
118
+ // CRITICAL: Prevent accumulation of queueMicrotask calls during rapid animation updates
119
+ if (!this.microtaskQueued) {
120
+ this.microtaskQueued = true;
121
+ queueMicrotask(() => {
122
+ this.microtaskQueued = false; // Reset flag when microtask executes
123
+ this.processAnimation();
124
+ this.eventBus.fireDraw();
125
+ });
126
+ }
127
+ }
128
+ else {
129
+ this.stopInterval();
130
+ }
131
+ }
132
+ stopInterval() {
133
+ cancelThrottledAnimationFramePrior(this.animFrameId);
134
+ // Reset microtask flag to ensure clean state
135
+ this.microtaskQueued = false;
136
+ }
137
+ }
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import { CanvasAnimation } from '../../../../../animation/canvas-animation';
7
+ import { CanvasBoundsContainer } from '../../../../../canvas/canvas-bounds-container';
8
+ import { FullChartConfig } from '../../../../../chart.config';
9
+ import EventBus from '../../../../../events/event-bus';
10
+ import { CanvasInputListenerComponent, Point } from '../../../../../inputlisteners/canvas-input-listener.component';
11
+ import { ScaleModel } from '../../../../../model/scale.model';
12
+ import { HitTestCanvasModel } from '../../../../../model/hit-test-canvas.model';
13
+ import { ChartPanComponent } from '../../../../../components/pan/chart-pan.component';
14
+ import { ChartAreaPanHandler, ChartPanningOptions } from '../../../../../components/chart/chart-area-pan.handler';
15
+ /**
16
+ * SafariChartAreaPanHandler is a class that handles the panning and zooming of the chart area for Safari.
17
+ */
18
+ export declare class SafariChartAreaPanHandler extends ChartAreaPanHandler {
19
+ protected bus: EventBus;
20
+ protected config: FullChartConfig;
21
+ protected scale: ScaleModel;
22
+ protected canvasInputListener: CanvasInputListenerComponent;
23
+ protected canvasBoundsContainer: CanvasBoundsContainer;
24
+ protected canvasAnimation: CanvasAnimation;
25
+ protected chartPanComponent: ChartPanComponent;
26
+ protected hitTestCanvasModel: HitTestCanvasModel;
27
+ protected currentPoint: Point;
28
+ xDraggedCandlesDelta: number;
29
+ lastXStart: number;
30
+ wheelThrottleTime: number;
31
+ private wheelSubscription;
32
+ private initFrameId;
33
+ private isActivated;
34
+ private lastWheelTime;
35
+ private wheelCount;
36
+ private consecutiveLowWheelEvents;
37
+ chartPanningOptions: ChartPanningOptions;
38
+ constructor(bus: EventBus, config: FullChartConfig, scale: ScaleModel, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, canvasAnimation: CanvasAnimation, chartPanComponent: ChartPanComponent, hitTestCanvasModel: HitTestCanvasModel);
39
+ /**
40
+ * This method is used to activate the zoom functionality of the canvas. It extends the doActivate method of the parent class.
41
+ * @protected
42
+ * @returns {void}
43
+ */
44
+ protected doActivate(): void;
45
+ /**
46
+ * Creates wheel subscription with optimized throttling
47
+ */
48
+ private createWheelSubscription;
49
+ /**
50
+ * Manual cleanup trigger for immediate performance recovery
51
+ */
52
+ triggerPerformanceCleanup(): void;
53
+ protected doDeactivate(): void;
54
+ }
@@ -0,0 +1,180 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import { animationFrameScheduler } from 'rxjs';
7
+ import { throttleTime, filter, debounceTime } from 'rxjs/operators';
8
+ import { CanvasElement } from '../../../../../canvas/canvas-bounds-container';
9
+ import { pixelsToUnits } from '../../../../../model/scaling/viewport.model';
10
+ import { deviceDetector } from '../../../../../utils/device/device-detector.utils';
11
+ import { ONE_FRAME_MS } from '../../../../../utils/numeric-constants.utils';
12
+ import { EVENT_RESIZED } from '../../../../../events/events';
13
+ import { DEFAULT_THROTTLE_MS, LARGE_SCREEN_PIXEL_THRESHOLD, LARGE_SCREEN_THROTTLE_MS, LOW_WHEEL_EVENTS_THRESHOLD, SAFARI_THROTTLE_MS, WHEEL_MONITORING_INTERVAL_MS, } from '../../safari-performance.model';
14
+ import { ChartAreaPanHandler } from '../../../../../components/chart/chart-area-pan.handler';
15
+ /**
16
+ * SafariChartAreaPanHandler is a class that handles the panning and zooming of the chart area for Safari.
17
+ */
18
+ export class SafariChartAreaPanHandler extends ChartAreaPanHandler {
19
+ constructor(bus, config, scale, canvasInputListener, canvasBoundsContainer, canvasAnimation, chartPanComponent, hitTestCanvasModel) {
20
+ super(bus, config, scale, canvasInputListener, canvasBoundsContainer, canvasAnimation, chartPanComponent, hitTestCanvasModel);
21
+ this.bus = bus;
22
+ this.config = config;
23
+ this.scale = scale;
24
+ this.canvasInputListener = canvasInputListener;
25
+ this.canvasBoundsContainer = canvasBoundsContainer;
26
+ this.canvasAnimation = canvasAnimation;
27
+ this.chartPanComponent = chartPanComponent;
28
+ this.hitTestCanvasModel = hitTestCanvasModel;
29
+ this.currentPoint = { x: 0, y: 0 };
30
+ this.xDraggedCandlesDelta = 0;
31
+ this.lastXStart = 0;
32
+ this.wheelThrottleTime = ONE_FRAME_MS;
33
+ this.wheelSubscription = null;
34
+ this.initFrameId = null;
35
+ this.isActivated = false;
36
+ this.lastWheelTime = 0;
37
+ this.wheelCount = 0;
38
+ this.consecutiveLowWheelEvents = 0;
39
+ this.chartPanningOptions = { horizontal: true, vertical: true };
40
+ }
41
+ /**
42
+ * This method is used to activate the zoom functionality of the canvas. It extends the doActivate method of the parent class.
43
+ * @protected
44
+ * @returns {void}
45
+ */
46
+ doActivate() {
47
+ if (this.isActivated) {
48
+ return;
49
+ }
50
+ this.isActivated = true;
51
+ super.doActivate();
52
+ this.canvasInputListener.initializeRectCache();
53
+ this.createWheelSubscription();
54
+ this.initFrameId = requestAnimationFrame(() => {
55
+ this.bus.fireDraw();
56
+ });
57
+ this.addRxSubscription(this.chartPanComponent.chartBaseModel.dataPrependSubject
58
+ .asObservable()
59
+ .subscribe(({ prependedCandlesWidth }) => {
60
+ this.lastXStart += prependedCandlesWidth;
61
+ }));
62
+ this.addRxSubscription(this.bus
63
+ .observe(EVENT_RESIZED)
64
+ .pipe(debounceTime(100))
65
+ .subscribe(() => {
66
+ if (this.scale && typeof this.scale.haltAnimation === 'function') {
67
+ this.scale.haltAnimation();
68
+ }
69
+ }));
70
+ }
71
+ /**
72
+ * Creates wheel subscription with optimized throttling
73
+ */
74
+ createWheelSubscription() {
75
+ if (this.wheelSubscription) {
76
+ this.wheelSubscription.unsubscribe();
77
+ this.wheelSubscription = null;
78
+ }
79
+ const allPanesHitTest = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
80
+ const canvasBounds = this.canvasBoundsContainer.getBounds(CanvasElement.CANVAS);
81
+ const totalPixels = canvasBounds.width * canvasBounds.height;
82
+ if (totalPixels > 0) {
83
+ if (totalPixels > LARGE_SCREEN_PIXEL_THRESHOLD) {
84
+ this.wheelThrottleTime = LARGE_SCREEN_THROTTLE_MS;
85
+ }
86
+ else {
87
+ this.wheelThrottleTime = SAFARI_THROTTLE_MS;
88
+ }
89
+ }
90
+ else {
91
+ this.wheelThrottleTime = DEFAULT_THROTTLE_MS;
92
+ }
93
+ this.wheelSubscription = this.canvasInputListener
94
+ .observeWheel(allPanesHitTest)
95
+ .pipe(filter(() => this.chartPanningOptions.horizontal && this.chartPanningOptions.vertical), filter((e) => {
96
+ const device = deviceDetector();
97
+ if (device === 'apple') {
98
+ const minDelta = 1.0;
99
+ return Math.abs(e.deltaY) > minDelta || Math.abs(e.deltaX) > minDelta;
100
+ }
101
+ return true;
102
+ }), throttleTime(this.wheelThrottleTime, animationFrameScheduler, { trailing: true, leading: true }))
103
+ .subscribe(e => {
104
+ const now = performance.now();
105
+ if (!this.lastWheelTime) {
106
+ this.lastWheelTime = now;
107
+ this.wheelCount = 0;
108
+ }
109
+ this.wheelCount++;
110
+ if (now - this.lastWheelTime > WHEEL_MONITORING_INTERVAL_MS) {
111
+ const wheelEventsPerSecond = Math.round((this.wheelCount * 1000) / (now - this.lastWheelTime));
112
+ if (wheelEventsPerSecond < LOW_WHEEL_EVENTS_THRESHOLD) {
113
+ this.consecutiveLowWheelEvents++;
114
+ if (this.consecutiveLowWheelEvents >= 1) {
115
+ this.triggerPerformanceCleanup();
116
+ this.consecutiveLowWheelEvents = 0;
117
+ }
118
+ }
119
+ else {
120
+ this.consecutiveLowWheelEvents = 0;
121
+ }
122
+ this.lastWheelTime = now;
123
+ this.wheelCount = 0;
124
+ }
125
+ const device = deviceDetector();
126
+ const direction = device === 'apple' || device === 'mobile' ? -1 : 1;
127
+ const deltaX = 0 + e.deltaX * direction;
128
+ const deltaY = 0 + e.deltaY * direction;
129
+ if (e.ctrlKey) {
130
+ const zoomSensitivity = this.calculateDynamicSesitivity(e, this.config.scale.zoomSensitivity.wheel);
131
+ this.zoomXHandler(e, zoomSensitivity);
132
+ this.bus.fireDraw();
133
+ return;
134
+ }
135
+ if (deltaY !== 0 && Math.abs(deltaY) > Math.abs(deltaX)) {
136
+ const zoomSensitivity = this.calculateDynamicSesitivity(e, this.config.scale.zoomSensitivity.wheel);
137
+ this.zoomXHandler(e, zoomSensitivity);
138
+ this.bus.fireDraw();
139
+ }
140
+ if (deltaX !== 0 && Math.abs(deltaX) > Math.abs(deltaY)) {
141
+ const unitsDelta = pixelsToUnits(deltaX, this.scale.zoomX);
142
+ this.scale.moveXStart(this.scale.xStart - unitsDelta);
143
+ this.bus.fireDraw();
144
+ return;
145
+ }
146
+ });
147
+ this.addRxSubscription(this.wheelSubscription);
148
+ }
149
+ /**
150
+ * Manual cleanup trigger for immediate performance recovery
151
+ */
152
+ triggerPerformanceCleanup() {
153
+ window.dispatchEvent(new Event('resize'));
154
+ if (window.gc) {
155
+ window.gc();
156
+ }
157
+ if (this.initFrameId) {
158
+ cancelAnimationFrame(this.initFrameId);
159
+ this.initFrameId = null;
160
+ }
161
+ if (this.scale && typeof this.scale.haltAnimation === 'function') {
162
+ this.scale.haltAnimation();
163
+ }
164
+ this.consecutiveLowWheelEvents = 0;
165
+ this.wheelCount = 0;
166
+ this.lastWheelTime = 0;
167
+ }
168
+ doDeactivate() {
169
+ if (this.wheelSubscription) {
170
+ this.wheelSubscription.unsubscribe();
171
+ this.wheelSubscription = null;
172
+ }
173
+ if (this.initFrameId) {
174
+ cancelAnimationFrame(this.initFrameId);
175
+ this.initFrameId = null;
176
+ }
177
+ this.isActivated = false;
178
+ super.doDeactivate();
179
+ }
180
+ }
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ export type SafariThrottleTimeMS = number;
7
+ /**
8
+ * Safari canvas performance limits because of Safari's GPU limits
9
+ */
10
+ export declare const SAFARI_CANVAS_LIMITS: {
11
+ readonly MAX_DIMENSION: 2048;
12
+ readonly MAX_TOTAL_PIXELS: 1800000;
13
+ readonly ZOOM_OPTIMIZED_PIXELS: 1200000;
14
+ };
15
+ export declare const LARGE_SCREEN_PIXEL_THRESHOLD = 2000000;
16
+ export declare const LARGE_SCREEN_THROTTLE_MS = 24;
17
+ export declare const SAFARI_THROTTLE_MS = 20;
18
+ export declare const DEFAULT_THROTTLE_MS = 16;
19
+ export declare const LOW_WHEEL_EVENTS_THRESHOLD = 10;
20
+ export declare const WHEEL_MONITORING_INTERVAL_MS = 1000;
21
+ /**
22
+ * Threshold for significant canvas area change to trigger subscription recreation
23
+ * Prevents unnecessary recreation for minor size adjustments
24
+ */
25
+ export declare const CANVAS_AREA_CHANGE_THRESHOLD = 50000;
26
+ export declare const SafariThrottleTimeMSMap: {
27
+ readonly MIN: 60;
28
+ readonly LOW: 80;
29
+ readonly MEDIUM: 100;
30
+ readonly HIGH: 120;
31
+ readonly MAX: 150;
32
+ };
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ /**
7
+ * Safari canvas performance limits because of Safari's GPU limits
8
+ */
9
+ export const SAFARI_CANVAS_LIMITS = {
10
+ MAX_DIMENSION: 2048,
11
+ MAX_TOTAL_PIXELS: 1800000,
12
+ ZOOM_OPTIMIZED_PIXELS: 1200000,
13
+ };
14
+ export const LARGE_SCREEN_PIXEL_THRESHOLD = 2000000; // 2M pixels
15
+ export const LARGE_SCREEN_THROTTLE_MS = 24;
16
+ export const SAFARI_THROTTLE_MS = 20;
17
+ export const DEFAULT_THROTTLE_MS = 16;
18
+ export const LOW_WHEEL_EVENTS_THRESHOLD = 10; // Minimum wheel events per second
19
+ export const WHEEL_MONITORING_INTERVAL_MS = 1000;
20
+ /**
21
+ * Threshold for significant canvas area change to trigger subscription recreation
22
+ * Prevents unnecessary recreation for minor size adjustments
23
+ */
24
+ export const CANVAS_AREA_CHANGE_THRESHOLD = 50000;
25
+ export const SafariThrottleTimeMSMap = {
26
+ MIN: 60,
27
+ LOW: 80,
28
+ MEDIUM: 100,
29
+ HIGH: 120,
30
+ MAX: 150,
31
+ };
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import { SafariThrottleTimeMS } from './safari-performance.model';
7
+ /**
8
+ * Safari Performance Optimization Utilities
9
+ *
10
+ * This module contains utilities specifically designed to address Safari performance issues
11
+ * during drag/zoom operations on charts.
12
+ */
13
+ /**
14
+ * Calculates optimal throttle time for hit-test wheel events based on canvas size and browser
15
+ * @param canvasArea - Total canvas area in pixels (width * height)
16
+ * @returns Throttle time in milliseconds
17
+ */
18
+ export declare function calculateHitTestThrottleTime(canvasArea: number): SafariThrottleTimeMS;
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import { SAFARI_CANVAS_LIMITS, SafariThrottleTimeMSMap } from './safari-performance.model';
7
+ /**
8
+ * Safari Performance Optimization Utilities
9
+ *
10
+ * This module contains utilities specifically designed to address Safari performance issues
11
+ * during drag/zoom operations on charts.
12
+ */
13
+ /**
14
+ * Calculates optimal throttle time for hit-test wheel events based on canvas size and browser
15
+ * @param canvasArea - Total canvas area in pixels (width * height)
16
+ * @returns Throttle time in milliseconds
17
+ */
18
+ export function calculateHitTestThrottleTime(canvasArea) {
19
+ if (canvasArea > SAFARI_CANVAS_LIMITS.ZOOM_OPTIMIZED_PIXELS) {
20
+ return SafariThrottleTimeMSMap.MAX;
21
+ }
22
+ else if (canvasArea > SAFARI_CANVAS_LIMITS.ZOOM_OPTIMIZED_PIXELS * 0.75) {
23
+ return SafariThrottleTimeMSMap.HIGH;
24
+ }
25
+ else if (canvasArea > SAFARI_CANVAS_LIMITS.ZOOM_OPTIMIZED_PIXELS * 0.5) {
26
+ return SafariThrottleTimeMSMap.MEDIUM;
27
+ }
28
+ else if (canvasArea > SAFARI_CANVAS_LIMITS.ZOOM_OPTIMIZED_PIXELS * 0.25) {
29
+ return SafariThrottleTimeMSMap.LOW;
30
+ }
31
+ else {
32
+ return SafariThrottleTimeMSMap.MIN;
33
+ }
34
+ }