@devexperts/dxcharts-lite 2.6.0 → 2.6.2

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 (43) hide show
  1. package/dist/chart/bootstrap.js +1 -1
  2. package/dist/chart/canvas/canvas-bounds-container.d.ts +5 -4
  3. package/dist/chart/canvas/canvas-bounds-container.js +8 -5
  4. package/dist/chart/chart.config.d.ts +48 -12
  5. package/dist/chart/chart.config.js +27 -6
  6. package/dist/chart/components/chart/chart-area-pan.handler.d.ts +3 -2
  7. package/dist/chart/components/chart/chart-area-pan.handler.js +5 -4
  8. package/dist/chart/components/cross_tool/cross-tool.component.js +2 -2
  9. package/dist/chart/components/cross_tool/cross-tool.drawer.d.ts +3 -1
  10. package/dist/chart/components/cross_tool/cross-tool.drawer.js +4 -3
  11. package/dist/chart/components/cross_tool/cross-tool.model.d.ts +6 -6
  12. package/dist/chart/components/cross_tool/cross-tool.model.js +42 -11
  13. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +3 -3
  14. package/dist/chart/components/events/events-custom-icons.d.ts +33 -0
  15. package/dist/chart/components/events/events-custom-icons.js +52 -0
  16. package/dist/chart/components/events/events.drawer.d.ts +5 -30
  17. package/dist/chart/components/events/events.drawer.js +33 -69
  18. package/dist/chart/components/high_low/high-low.drawer.js +1 -1
  19. package/dist/chart/components/pane/pane-manager.component.d.ts +6 -0
  20. package/dist/chart/components/pane/pane-manager.component.js +24 -3
  21. package/dist/chart/components/pane/pane.component.d.ts +16 -5
  22. package/dist/chart/components/pane/pane.component.js +27 -4
  23. package/dist/chart/components/resizer/bar-resizer.component.d.ts +1 -0
  24. package/dist/chart/components/resizer/bar-resizer.component.js +1 -0
  25. package/dist/chart/components/x_axis/x-axis-draw.functions.js +2 -2
  26. package/dist/chart/components/x_axis/x-axis-scale.handler.d.ts +1 -0
  27. package/dist/chart/components/x_axis/x-axis-scale.handler.js +37 -8
  28. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +2 -2
  29. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.d.ts +3 -1
  30. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.js +4 -1
  31. package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +2 -0
  32. package/dist/chart/components/y_axis/y-axis-scale.handler.js +12 -0
  33. package/dist/chart/inputhandlers/cross-event-producer.component.d.ts +22 -0
  34. package/dist/chart/inputhandlers/cross-event-producer.component.js +11 -1
  35. package/dist/chart/inputhandlers/hover-producer.component.d.ts +5 -3
  36. package/dist/chart/inputhandlers/hover-producer.component.js +70 -16
  37. package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +10 -0
  38. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +18 -0
  39. package/dist/chart/inputlisteners/canvas-input-listener.component.js +2 -7
  40. package/dist/chart/model/candle-series.model.js +1 -1
  41. package/dist/chart/model/data-series.model.js +18 -0
  42. package/dist/dxchart.min.js +4 -4
  43. package/package.json +1 -1
@@ -5,12 +5,12 @@
5
5
  */
6
6
  import { Bounds } from '../../model/bounds.model';
7
7
  import { CanvasBoundsContainer } from '../../canvas/canvas-bounds-container';
8
- import { CustomIcon, FullChartConfig } from '../../chart.config';
8
+ import { FullChartConfig, EventColors } from '../../chart.config';
9
9
  import { CanvasModel } from '../../model/canvas.model';
10
10
  import { Drawer } from '../../drawers/drawing-manager';
11
11
  import { DateTimeFormatter } from '../../model/date-time.formatter';
12
12
  import { ChartModel } from '../chart/chart.model';
13
- import { EconomicEvent, EventsModel, EventType, EventWithId } from './events.model';
13
+ import { EconomicEvent, EventsModel, EventWithId } from './events.model';
14
14
  export declare class EventsDrawer implements Drawer {
15
15
  private canvasModel;
16
16
  private chartModel;
@@ -20,22 +20,6 @@ export declare class EventsDrawer implements Drawer {
20
20
  private formatterProvider;
21
21
  private customIcons;
22
22
  constructor(canvasModel: CanvasModel, chartModel: ChartModel, config: FullChartConfig, canvasBoundsContainer: CanvasBoundsContainer, model: EventsModel, formatterProvider: () => DateTimeFormatter);
23
- /**
24
- * Creates a custom icon for a given event type.
25
- * @param {EventType} type - The type of the event.
26
- * @param {CustomIcon} [icon] - The custom icon object containing the normal and hover images.
27
- * @returns {void}
28
- */
29
- createCustomIcon(type: EventType, icon?: CustomIcon): void;
30
- /**
31
- * Creates an icon image from a string containing SVG data.
32
- * @param {string} iconString - The string containing SVG data.
33
- * @returns {Object} An object containing an Image object and the height of the SVG element.
34
- */
35
- createIconImage(iconString: string): {
36
- img: HTMLImageElement;
37
- svgHeight: number;
38
- };
39
23
  /**
40
24
  * Draws events on the chart canvas if they are visible according to the configuration.
41
25
  * The events are filtered by type and then iterated over to draw them on the chart.
@@ -44,25 +28,16 @@ export declare class EventsDrawer implements Drawer {
44
28
  * @returns {void}
45
29
  */
46
30
  draw(): void;
47
- /**
48
- * Draws a custom SVG event on a canvas context.
49
- * @param {CanvasRenderingContext2D} ctx - The canvas context to draw on.
50
- * @param {number} x - The x coordinate of the event.
51
- * @param {Bounds} bounds - The bounds of the event.
52
- * @param {EventWithId} event - The event to draw.
53
- * @returns {void}
54
- */
55
- drawCustomSvgEvent(ctx: CanvasRenderingContext2D, x: number, bounds: Bounds, event: EventWithId): void;
56
31
  /**
57
32
  * Draws a default event on a canvas context.
58
33
  * @param {CanvasRenderingContext2D} ctx - The canvas context to draw on.
59
34
  * @param {number} x - The x coordinate of the event.
60
35
  * @param {Bounds} bounds - The bounds of the event.
61
36
  * @param {EventWithId} event - The event to draw.
62
- * @param {string} color - The color of the event.
37
+ * @param {EventColors} colors - The colors of the event.
63
38
  * @returns {void}
64
39
  */
65
- drawDefaultEvent(ctx: CanvasRenderingContext2D, x: number, bounds: Bounds, event: EventWithId, color: string): void;
40
+ drawDefaultEvent(ctx: CanvasRenderingContext2D, x: number, bounds: Bounds, event: EventWithId, colors: EventColors): void;
66
41
  /**
67
42
  * This function is responsible for drawing a label on the canvas at a given x coordinate. The label contains a formatted timestamp of a given event. The function takes two parameters: x, which is the x coordinate where the label will be drawn, and event, which is an object containing information about the event, including its timestamp and type.
68
43
  * The function first gets the canvas context and the bounds of the x-axis. It then retrieves the font family, font height, and top padding from the configuration object. The y coordinate of the label is calculated based on the font height, top padding, and the y coordinate of the x-axis bounds. The font is set using the retrieved font family and font height.
@@ -81,6 +56,6 @@ export declare class EventsDrawer implements Drawer {
81
56
  * Returns the size of an event based on its style
82
57
  * @param {EconomicEvent} event - The event to get the size of
83
58
  * @returns {number} - The size of the event
84
-
59
+
85
60
  */
86
61
  export declare function getEventSize(event: EconomicEvent): number;
@@ -4,12 +4,18 @@
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
6
  import { CanvasElement } from '../../canvas/canvas-bounds-container';
7
+ import { createCustomIcon, drawCustomSvgIcon, getIconHash } from './events-custom-icons';
7
8
  const eventsSizesDict = {
8
9
  'rhombus-small': 4,
9
10
  rhombus: 6,
10
11
  'rhombus-large': 8,
11
12
  };
12
- const getIconHash = (type, state) => `${type}_${state}`;
13
+ const iconTypes = [
14
+ 'earnings',
15
+ 'dividends',
16
+ 'splits',
17
+ 'conference-calls',
18
+ ];
13
19
  export class EventsDrawer {
14
20
  constructor(canvasModel, chartModel, config, canvasBoundsContainer, model, formatterProvider) {
15
21
  this.canvasModel = canvasModel;
@@ -22,48 +28,14 @@ export class EventsDrawer {
22
28
  this.customIcons = {};
23
29
  const iconsConfig = this.config.components.events.icons;
24
30
  if (iconsConfig) {
25
- this.createCustomIcon('earnings', iconsConfig.earnings);
26
- this.createCustomIcon('dividends', iconsConfig.dividends);
27
- this.createCustomIcon('splits', iconsConfig.splits);
28
- this.createCustomIcon('conference-calls', iconsConfig.conferenceCalls);
29
- }
30
- }
31
- /**
32
- * Creates a custom icon for a given event type.
33
- * @param {EventType} type - The type of the event.
34
- * @param {CustomIcon} [icon] - The custom icon object containing the normal and hover images.
35
- * @returns {void}
36
- */
37
- createCustomIcon(type, icon) {
38
- if (icon) {
39
- const normal = this.createIconImage(icon.normal);
40
- const hover = this.createIconImage(icon.hover);
41
- this.customIcons[getIconHash(type, 'normal')] = normal;
42
- this.customIcons[getIconHash(type, 'hover')] = hover;
43
- }
44
- }
45
- /**
46
- * Creates an icon image from a string containing SVG data.
47
- * @param {string} iconString - The string containing SVG data.
48
- * @returns {Object} An object containing an Image object and the height of the SVG element.
49
- */
50
- createIconImage(iconString) {
51
- var _a;
52
- const parser = new DOMParser();
53
- const svgSelector = parser.parseFromString(iconString, 'text/html').querySelector('svg');
54
- let svgHeight = 0;
55
- if (svgSelector) {
56
- svgHeight = parseInt((_a = svgSelector.getAttribute('height')) !== null && _a !== void 0 ? _a : '', 10);
31
+ iconTypes.forEach(type => {
32
+ const customIcon = createCustomIcon(type, iconsConfig[type]);
33
+ if (customIcon) {
34
+ this.customIcons[getIconHash(customIcon.type, 'normal')] = customIcon.normal;
35
+ this.customIcons[getIconHash(customIcon.type, 'hover')] = customIcon.hover;
36
+ }
37
+ });
57
38
  }
58
- const svg64 = btoa(iconString);
59
- const b64Start = 'data:image/svg+xml;base64,';
60
- const image64 = b64Start + svg64;
61
- const img = new Image();
62
- img.src = image64;
63
- return {
64
- img,
65
- svgHeight,
66
- };
67
39
  }
68
40
  /**
69
41
  * Draws events on the chart canvas if they are visible according to the configuration.
@@ -83,20 +55,28 @@ export class EventsDrawer {
83
55
  this.model.events
84
56
  .filter(e => this.config.components.events.eventsVisibility[e.type])
85
57
  .forEach(event => {
58
+ var _a, _b, _c, _d;
86
59
  const x = this.chartModel.candleFromTimestamp(event.timestamp).xCenter(this.chartModel.scale);
87
60
  if (x > chartBounds.x && x < chartBounds.x + chartBounds.width) {
88
- const color = this.config.colors.events[event.type].color;
89
- ctx.strokeStyle = color;
61
+ const colors = this.config.colors.events[event.type];
62
+ ctx.strokeStyle = (_b = (_a = colors.line) !== null && _a !== void 0 ? _a : colors.normal) !== null && _b !== void 0 ? _b : colors.color;
90
63
  // check custom icon in cache
91
64
  if (this.customIcons[getIconHash(event.type, 'hover')] !== undefined) {
92
- this.drawCustomSvgEvent(ctx, x, bounds, event);
65
+ const point = { x, y: bounds.y + bounds.height / 2 };
66
+ const isHovered = this.model.hoveredEvent.getValue() === event;
67
+ drawCustomSvgIcon(ctx, this.customIcons, point, event.type, isHovered);
93
68
  }
94
69
  else {
95
- this.drawDefaultEvent(ctx, x, bounds, event, color);
70
+ this.drawDefaultEvent(ctx, x, bounds, event, colors);
96
71
  }
97
72
  // draw vertical line and label for the hovered event
98
73
  if (this.model.hoveredEvent.getValue() === event) {
74
+ const line = this.config.components.events.line;
75
+ const width = line && line[event.type] && ((_c = line[event.type]) === null || _c === void 0 ? void 0 : _c.width);
76
+ const dash = line && line[event.type] && ((_d = line[event.type]) === null || _d === void 0 ? void 0 : _d.dash);
77
+ ctx.lineWidth = width !== null && width !== void 0 ? width : 1;
99
78
  ctx.beginPath();
79
+ ctx.setLineDash(dash !== null && dash !== void 0 ? dash : []);
100
80
  ctx.moveTo(x, chartBounds.y);
101
81
  ctx.lineTo(x, bounds.y + bounds.height / 2);
102
82
  ctx.stroke();
@@ -109,37 +89,19 @@ export class EventsDrawer {
109
89
  });
110
90
  ctx.restore();
111
91
  }
112
- /**
113
- * Draws a custom SVG event on a canvas context.
114
- * @param {CanvasRenderingContext2D} ctx - The canvas context to draw on.
115
- * @param {number} x - The x coordinate of the event.
116
- * @param {Bounds} bounds - The bounds of the event.
117
- * @param {EventWithId} event - The event to draw.
118
- * @returns {void}
119
- */
120
- drawCustomSvgEvent(ctx, x, bounds, event) {
121
- const y = bounds.y + bounds.height / 2;
122
- const normal = this.customIcons[getIconHash(event.type, 'normal')];
123
- const hover = this.customIcons[getIconHash(event.type, 'hover')];
124
- if (this.model.hoveredEvent.getValue() === event) {
125
- ctx.drawImage(hover.img, x - hover.svgHeight / 2, y - hover.svgHeight / 2);
126
- }
127
- else {
128
- ctx.drawImage(normal.img, x - normal.svgHeight / 2, y - normal.svgHeight / 2);
129
- }
130
- }
131
92
  /**
132
93
  * Draws a default event on a canvas context.
133
94
  * @param {CanvasRenderingContext2D} ctx - The canvas context to draw on.
134
95
  * @param {number} x - The x coordinate of the event.
135
96
  * @param {Bounds} bounds - The bounds of the event.
136
97
  * @param {EventWithId} event - The event to draw.
137
- * @param {string} color - The color of the event.
98
+ * @param {EventColors} colors - The colors of the event.
138
99
  * @returns {void}
139
100
  */
140
- drawDefaultEvent(ctx, x, bounds, event, color) {
101
+ drawDefaultEvent(ctx, x, bounds, event, colors) {
102
+ var _a, _b, _c;
141
103
  const y = bounds.y + bounds.height / 2;
142
- ctx.fillStyle = color;
104
+ ctx.fillStyle = (_a = colors.normal) !== null && _a !== void 0 ? _a : colors.color;
143
105
  // draw figure
144
106
  ctx.lineWidth = 1.5; // 1.5 pixels
145
107
  const size = getEventSize(event);
@@ -150,9 +112,11 @@ export class EventsDrawer {
150
112
  ctx.lineTo(x, y + size);
151
113
  ctx.closePath();
152
114
  if (this.model.hoveredEvent.getValue() === event) {
115
+ ctx.fillStyle = (_b = colors.hover) !== null && _b !== void 0 ? _b : colors.color;
153
116
  ctx.fill();
154
117
  }
155
118
  else {
119
+ ctx.strokeStyle = (_c = colors.normal) !== null && _c !== void 0 ? _c : colors.color;
156
120
  ctx.stroke();
157
121
  }
158
122
  }
@@ -193,7 +157,7 @@ export class EventsDrawer {
193
157
  * Returns the size of an event based on its style
194
158
  * @param {EconomicEvent} event - The event to get the size of
195
159
  * @returns {number} - The size of the event
196
-
160
+
197
161
  */
198
162
  export function getEventSize(event) {
199
163
  return eventsSizesDict[event.style];
@@ -73,7 +73,7 @@ export class HighLowDrawer {
73
73
  */
74
74
  getMarkerText(yValue, type) {
75
75
  const formattedValue = this.chartModel.pane.regularFormatter(yValue);
76
- const prefix = type === 'high' ? 'H:' : 'L:';
76
+ const prefix = type === 'high' ? this.config.components.highLow.prefix.high : this.config.components.highLow.prefix.low;
77
77
  return `${prefix} ${formattedValue}`;
78
78
  }
79
79
  /**
@@ -24,6 +24,7 @@ import { PaneComponent } from './pane.component';
24
24
  import { DataSeriesModel } from '../../model/data-series.model';
25
25
  import { HitTestCanvasModel } from '../../model/hit-test-canvas.model';
26
26
  import { ChartResizeHandler } from '../../inputhandlers/chart-resize.handler';
27
+ export type MoveDataSeriesToPaneDirection = 'above' | 'below';
27
28
  export declare class PaneManager extends ChartBaseElement {
28
29
  private chartBaseModel;
29
30
  private dynamicObjectsCanvasModel;
@@ -70,6 +71,7 @@ export declare class PaneManager extends ChartBaseElement {
70
71
  /**
71
72
  * Creates sub-plot on the chart with y-axis
72
73
  * @param uuid
74
+ * @param {AtLeastOne<YExtentCreationOptions>} options
73
75
  * @returns
74
76
  */
75
77
  createPane(uuid?: string, options?: AtLeastOne<YExtentCreationOptions>): PaneComponent;
@@ -107,6 +109,10 @@ export declare class PaneManager extends ChartBaseElement {
107
109
  * Shows a pane, use if the pane is hidden
108
110
  */
109
111
  showPane(paneUUID: string): void;
112
+ /**
113
+ * Move data series to a certain pane, or create a new one if no pane is found
114
+ */
115
+ moveDataSeriesToPane(dataSeries: DataSeriesModel[], initialPane: PaneComponent, initialExtent: YExtentComponent, paneUUID?: string, extent?: YExtentComponent, direction?: MoveDataSeriesToPaneDirection, index?: number): void;
110
116
  /**
111
117
  * Adds cursors to the chart elements based on the provided uuid and cursor type.
112
118
  * @private
@@ -8,7 +8,7 @@ import { CHART_UUID, CanvasElement } from '../../canvas/canvas-bounds-container'
8
8
  import { ChartBaseElement } from '../../model/chart-base-element';
9
9
  import { uuid as generateUuid } from '../../utils/uuid.utils';
10
10
  import { createHighLowOffsetCalculator } from '../chart/data-series.high-low-provider';
11
- import { BarResizerComponent } from '../resizer/bar-resizer.component';
11
+ import { BarResizerComponent, RESIZER_HIT_TEST_EXTENSION } from '../resizer/bar-resizer.component';
12
12
  import { createDefaultYExtentHighLowProvider, } from './extent/y-extent-component';
13
13
  import { PaneHitTestController } from './pane-hit-test.controller';
14
14
  import { PaneComponent } from './pane.component';
@@ -63,7 +63,7 @@ export class PaneManager extends ChartBaseElement {
63
63
  */
64
64
  addResizer(uuid) {
65
65
  const resizerHT = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.PANE_UUID_RESIZER(uuid), {
66
- extensionY: this.config.components.paneResizer.dragZone,
66
+ extensionY: this.config.components.paneResizer.dragZone + RESIZER_HIT_TEST_EXTENSION,
67
67
  });
68
68
  const dragPredicate = () => this.chartBaseModel.mainVisualPoints.length !== 0;
69
69
  const dragTick = () => {
@@ -90,6 +90,7 @@ export class PaneManager extends ChartBaseElement {
90
90
  /**
91
91
  * Creates sub-plot on the chart with y-axis
92
92
  * @param uuid
93
+ * @param {AtLeastOne<YExtentCreationOptions>} options
93
94
  * @returns
94
95
  */
95
96
  createPane(uuid = generateUuid(), options) {
@@ -188,6 +189,26 @@ export class PaneManager extends ChartBaseElement {
188
189
  this.canvasBoundsContainer.showPaneBounds(paneUUID);
189
190
  this.recalculateState();
190
191
  }
192
+ /**
193
+ * Move data series to a certain pane, or create a new one if no pane is found
194
+ */
195
+ moveDataSeriesToPane(dataSeries, initialPane, initialExtent, paneUUID, extent, direction, index = 0) {
196
+ const pane = paneUUID && this.panes[paneUUID];
197
+ if (!pane) {
198
+ const order = direction && direction === 'above' ? index : this.panesOrder.length + index;
199
+ const newPane = this.createPane(paneUUID, { order });
200
+ newPane.moveDataSeriesToExistingExtentComponent(dataSeries, initialPane, initialExtent, newPane.mainExtent);
201
+ initialPane.yExtentComponents.length === 0 && this.removePane(initialPane.uuid);
202
+ return;
203
+ }
204
+ if (extent) {
205
+ pane.moveDataSeriesToExistingExtentComponent(dataSeries, initialPane, initialExtent, extent);
206
+ }
207
+ else {
208
+ pane.moveDataSeriesToNewExtentComponent(dataSeries, initialPane, initialExtent, initialExtent.yAxis.state.align);
209
+ }
210
+ initialPane.yExtentComponents.length === 0 && this.removePane(initialPane.uuid);
211
+ }
191
212
  /**
192
213
  * Adds cursors to the chart elements based on the provided uuid and cursor type.
193
214
  * @private
@@ -200,7 +221,7 @@ export class PaneManager extends ChartBaseElement {
200
221
  const paneResizer = CanvasElement.PANE_UUID_RESIZER(uuid);
201
222
  this.cursorHandler.setCursorForCanvasEl(pane, cursor);
202
223
  this.config.components.paneResizer.visible &&
203
- this.cursorHandler.setCursorForCanvasEl(paneResizer, this.config.components.paneResizer.cursor, this.config.components.paneResizer.dragZone);
224
+ this.cursorHandler.setCursorForCanvasEl(paneResizer, this.config.components.paneResizer.cursor, this.config.components.paneResizer.dragZone + RESIZER_HIT_TEST_EXTENSION);
204
225
  return () => {
205
226
  this.cursorHandler.removeCursorForCanvasEl(pane);
206
227
  this.config.components.paneResizer.visible && this.cursorHandler.removeCursorForCanvasEl(paneResizer);
@@ -7,7 +7,7 @@ import { Subject } from 'rxjs';
7
7
  import { CanvasAnimation } from '../../animation/canvas-animation';
8
8
  import { CanvasBoundsContainer, HitBoundsTest } from '../../canvas/canvas-bounds-container';
9
9
  import { CursorHandler } from '../../canvas/cursor.handler';
10
- import { FullChartConfig } from '../../chart.config';
10
+ import { FullChartConfig, YAxisAlign } from '../../chart.config';
11
11
  import { DrawingManager } from '../../drawers/drawing-manager';
12
12
  import EventBus from '../../events/event-bus';
13
13
  import { CanvasInputListenerComponent } from '../../inputlisteners/canvas-input-listener.component';
@@ -51,6 +51,7 @@ export declare class PaneComponent extends ChartBaseElement {
51
51
  */
52
52
  ht: HitBoundsTest;
53
53
  yExtentComponents: YExtentComponent[];
54
+ yExtentComponentsChangedSubject: Subject<void>;
54
55
  get scale(): ScaleModel;
55
56
  get yAxis(): YAxisComponent;
56
57
  get dataSeries(): DataSeriesModel<import("../../model/data-series.model").DataSeriesPoint, import("../../model/data-series.model").VisualSeriesPoint>[];
@@ -68,8 +69,10 @@ export declare class PaneComponent extends ChartBaseElement {
68
69
  /**
69
70
  * Creates a new GridComponent instance with the provided parameters.
70
71
  * @param {string} uuid - The unique identifier of the pane.
71
- * @param {ScaleModel} scaleModel - The scale model used to calculate the scale of the grid.
72
- * @param {NumericYAxisLabelsGenerator} yAxisLabelsGenerator - The generator used to create the labels for the y-axis.
72
+ * @param {ScaleModel} scale - The scale model used to calculate the scale of the grid.
73
+ * @param {YAxisConfig} yAxisState - y Axis Config
74
+ * @param {() => NumericAxisLabel[]} yAxisLabelsGetter
75
+ * @param {() => Unit} yAxisBaselineGetter
73
76
  * @returns {GridComponent} - The newly created GridComponent instance.
74
77
  */
75
78
  private createGridComponent;
@@ -77,13 +80,21 @@ export declare class PaneComponent extends ChartBaseElement {
77
80
  * Creates a handler for Y-axis panning of the chart.
78
81
  * @private
79
82
  * @param {string} uuid - The unique identifier of the chart pane.
80
- * @param {ScaleModel} scaleModel - The scale model of the chart.
81
- * @returns {Unsubscriber}
83
+ * @param {ScaleModel} scale - The scale model of the chart.
84
+ * @returns [Unsubscriber, DragNDropYComponent]
82
85
  */
83
86
  private createYPanHandler;
84
87
  private addCursors;
85
88
  createExtentComponent(options?: AtLeastOne<YExtentCreationOptions>): YExtentComponent;
86
89
  removeExtentComponent(extentComponent: YExtentComponent): void;
90
+ /**
91
+ * Create new pane extent and attach data series to it
92
+ */
93
+ moveDataSeriesToNewExtentComponent(dataSeries: DataSeriesModel[], initialPane: PaneComponent, initialExtent: YExtentComponent, align?: YAxisAlign): void;
94
+ /**
95
+ * Attach data series to existing y axis extent
96
+ */
97
+ moveDataSeriesToExistingExtentComponent(dataSeries: DataSeriesModel[], initialPane: PaneComponent, initialExtent: YExtentComponent, extentComponent: YExtentComponent): void;
87
98
  /**
88
99
  * This method updates the view by calling the doAutoScale method of the scaleModel and firing the Draw event using the eventBus.
89
100
  * @private
@@ -3,6 +3,7 @@
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 } from 'rxjs';
6
7
  import { distinctUntilChanged } from 'rxjs/operators';
7
8
  import { areBoundsChanged, CanvasElement, } from '../../canvas/canvas-bounds-container';
8
9
  import { ChartBaseElement } from '../../model/chart-base-element';
@@ -47,6 +48,7 @@ export class PaneComponent extends ChartBaseElement {
47
48
  this.hitTestCanvasModel = hitTestCanvasModel;
48
49
  this.chartResizeHandler = chartResizeHandler;
49
50
  this.yExtentComponents = [];
51
+ this.yExtentComponentsChangedSubject = new Subject();
50
52
  this.getYAxisBounds = () => {
51
53
  return this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID_Y_AXIS(this.uuid));
52
54
  };
@@ -84,8 +86,10 @@ export class PaneComponent extends ChartBaseElement {
84
86
  /**
85
87
  * Creates a new GridComponent instance with the provided parameters.
86
88
  * @param {string} uuid - The unique identifier of the pane.
87
- * @param {ScaleModel} scaleModel - The scale model used to calculate the scale of the grid.
88
- * @param {NumericYAxisLabelsGenerator} yAxisLabelsGenerator - The generator used to create the labels for the y-axis.
89
+ * @param {ScaleModel} scale - The scale model used to calculate the scale of the grid.
90
+ * @param {YAxisConfig} yAxisState - y Axis Config
91
+ * @param {() => NumericAxisLabel[]} yAxisLabelsGetter
92
+ * @param {() => Unit} yAxisBaselineGetter
89
93
  * @returns {GridComponent} - The newly created GridComponent instance.
90
94
  */
91
95
  createGridComponent(uuid, scale, yAxisState, yAxisLabelsGetter, yAxisBaselineGetter) {
@@ -97,8 +101,8 @@ export class PaneComponent extends ChartBaseElement {
97
101
  * Creates a handler for Y-axis panning of the chart.
98
102
  * @private
99
103
  * @param {string} uuid - The unique identifier of the chart pane.
100
- * @param {ScaleModel} scaleModel - The scale model of the chart.
101
- * @returns {Unsubscriber}
104
+ * @param {ScaleModel} scale - The scale model of the chart.
105
+ * @returns [Unsubscriber, DragNDropYComponent]
102
106
  */
103
107
  createYPanHandler(uuid, scale) {
104
108
  const chartPaneId = CanvasElement.PANE_UUID(uuid);
@@ -140,6 +144,7 @@ export class PaneComponent extends ChartBaseElement {
140
144
  yExtentComponent.activate();
141
145
  this.yExtentComponents.push(yExtentComponent);
142
146
  this.canvasBoundsContainer.updateYAxisWidths();
147
+ this.yExtentComponentsChangedSubject.next();
143
148
  return yExtentComponent;
144
149
  }
145
150
  removeExtentComponent(extentComponent) {
@@ -148,6 +153,24 @@ export class PaneComponent extends ChartBaseElement {
148
153
  // re-index extents
149
154
  this.yExtentComponents.forEach((c, idx) => (c.idx = idx));
150
155
  this.canvasBoundsContainer.updateYAxisWidths();
156
+ this.yExtentComponentsChangedSubject.next();
157
+ }
158
+ /**
159
+ * Create new pane extent and attach data series to it
160
+ */
161
+ moveDataSeriesToNewExtentComponent(dataSeries, initialPane, initialExtent, align = 'right') {
162
+ const extent = this.createExtentComponent();
163
+ extent.yAxis.setYAxisAlign(align);
164
+ dataSeries.forEach(series => series.moveToExtent(extent));
165
+ initialExtent.dataSeries.size === 0 && initialPane.removeExtentComponent(initialExtent);
166
+ }
167
+ /**
168
+ * Attach data series to existing y axis extent
169
+ */
170
+ moveDataSeriesToExistingExtentComponent(dataSeries, initialPane, initialExtent, extentComponent) {
171
+ dataSeries.forEach(series => series.moveToExtent(extentComponent));
172
+ initialExtent.dataSeries.size === 0 && initialPane.removeExtentComponent(initialExtent);
173
+ this.yExtentComponentsChangedSubject.next();
151
174
  }
152
175
  /**
153
176
  * This method updates the view by calling the doAutoScale method of the scaleModel and firing the Draw event using the eventBus.
@@ -14,6 +14,7 @@ import { CanvasInputListenerComponent } from '../../inputlisteners/canvas-input-
14
14
  import { ChartPanComponent } from '../pan/chart-pan.component';
15
15
  import { BoundsProvider } from '../../model/bounds.model';
16
16
  import { HitTestCanvasModel } from '../../model/hit-test-canvas.model';
17
+ export declare const RESIZER_HIT_TEST_EXTENSION: number;
17
18
  /**
18
19
  * Bar separator between panes.
19
20
  * Used to resize the areas height or just draw a fixed line.
@@ -9,6 +9,7 @@ import { DynamicDrawerType } from '../../drawers/drawing-manager';
9
9
  import { ChartBaseElement } from '../../model/chart-base-element';
10
10
  import { DragNDropYComponent } from '../dran-n-drop_helper/drag-n-drop-y.component';
11
11
  import { BarResizerDrawer } from './bar-resizer.drawer';
12
+ export const RESIZER_HIT_TEST_EXTENSION = 8;
12
13
  /**
13
14
  * Bar separator between panes.
14
15
  * Used to resize the areas height or just draw a fixed line.
@@ -3,7 +3,7 @@
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 { CanvasElement } from '../../canvas/canvas-bounds-container';
6
+ import { CanvasElement, X_AXIS_MOBILE_PADDING } from '../../canvas/canvas-bounds-container';
7
7
  const DEFAULT_X_LABEL_PADDING = { x: 4, y: 4 };
8
8
  /**
9
9
  * Draws the label on X axis.
@@ -50,7 +50,7 @@ export function drawXAxisLabel(ctx, canvasBoundsContainer, config, label) {
50
50
  }
51
51
  ctx.fillStyle = label.color;
52
52
  const xTextPos = boxStart + DEFAULT_X_LABEL_PADDING.x;
53
- const yTextPos = xAxisBounds.y + offsetTop + fontSize; // -2 for vertical adjustment
53
+ const yTextPos = xAxisBounds.y + offsetTop + fontSize + X_AXIS_MOBILE_PADDING / 2;
54
54
  ctx.fillText(label.text, xTextPos, yTextPos);
55
55
  ctx.restore();
56
56
  }
@@ -24,6 +24,7 @@ export declare class XAxisScaleHandler extends ChartBaseElement {
24
24
  private hitTest;
25
25
  private hitTestCanvasModel;
26
26
  lastXStart: Unit;
27
+ lastXEnd: Unit;
27
28
  lastXWidth: Unit;
28
29
  lastXPxWidth: Pixel;
29
30
  private dblClickCallback;
@@ -6,6 +6,8 @@
6
6
  import { ChartBaseElement } from '../../model/chart-base-element';
7
7
  import { CanvasElement } from '../../canvas/canvas-bounds-container';
8
8
  import { DragNDropXComponent } from '../dran-n-drop_helper/drag-n-drop-x.component';
9
+ // if you drag full X width from left to right - you will have x3 zoom, and vice-versa
10
+ const FULL_X_WIDTH_ZOOM_FACTOR = 3;
9
11
  /**
10
12
  * Handles the mouse drag on X axis - to zoom the viewport horizontally.
11
13
  * @doc-tags scaling,zoom,viewport
@@ -21,10 +23,12 @@ export class XAxisScaleHandler extends ChartBaseElement {
21
23
  this.hitTest = hitTest;
22
24
  this.hitTestCanvasModel = hitTestCanvasModel;
23
25
  this.lastXStart = 0;
26
+ this.lastXEnd = 0;
24
27
  this.lastXWidth = 0;
25
28
  this.lastXPxWidth = 0;
26
29
  this.onXDragStart = () => {
27
30
  this.lastXStart = this.scale.xStart;
31
+ this.lastXEnd = this.scale.xEnd;
28
32
  this.lastXWidth = this.scale.xEnd - this.scale.xStart;
29
33
  const bounds = this.canvasBoundsContainer.getBounds(CanvasElement.X_AXIS);
30
34
  this.lastXPxWidth = bounds.width - this.canvasInputListener.currentPoint.x;
@@ -32,16 +36,41 @@ export class XAxisScaleHandler extends ChartBaseElement {
32
36
  this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(false);
33
37
  };
34
38
  this.onXDragTick = (dragInfo) => {
35
- const { delta: absoluteXDelta } = dragInfo;
36
- const newPxWidth = this.lastXPxWidth - absoluteXDelta;
37
- // cursor goes beyond x-axis - maximum scale is reached
38
- if (newPxWidth < 0) {
39
+ let { delta: absoluteXDelta } = dragInfo;
40
+ // mouse click or single tap drag
41
+ if (!this.touches || this.touches.length === 1) {
42
+ const newPxWidth = this.lastXPxWidth - absoluteXDelta;
43
+ // cursor goes beyond x-axis - maximum scale is reached
44
+ if (newPxWidth < 0) {
45
+ return;
46
+ }
47
+ const xZoomMult = this.lastXPxWidth / newPxWidth;
48
+ const newWidth = this.lastXWidth * xZoomMult;
49
+ const newXStart = this.lastXStart + (this.lastXWidth - newWidth);
50
+ this.scale.setXScale(newXStart, this.scale.xEnd);
39
51
  return;
40
52
  }
41
- const xZoomMult = this.lastXPxWidth / newPxWidth;
42
- const newWidth = this.lastXWidth * xZoomMult;
43
- const newXStart = this.lastXStart + (this.lastXWidth - newWidth);
44
- this.scale.setXScale(newXStart, this.scale.xEnd);
53
+ // if multitouch - take the first two touch events and apply delta the following way:
54
+ // the touch on the left keeps the initial delta because left => right gesture
55
+ // the touch on the right has the reversed delta because the gesture is right => left
56
+ if (this.touches.length > 1) {
57
+ const left = Math.min(this.touches[0].clientX, this.touches[1].clientX);
58
+ absoluteXDelta = left === this.touches[0].clientX ? absoluteXDelta : -absoluteXDelta;
59
+ let xZoomMult;
60
+ if (absoluteXDelta < 0) {
61
+ xZoomMult = 1 / (1 + (-absoluteXDelta / this.lastXPxWidth) * (FULL_X_WIDTH_ZOOM_FACTOR - 1));
62
+ }
63
+ else {
64
+ xZoomMult = 1 + (absoluteXDelta / this.lastXPxWidth) * (FULL_X_WIDTH_ZOOM_FACTOR - 1);
65
+ }
66
+ const newXWidth = this.lastXWidth * xZoomMult;
67
+ const delta = (newXWidth - this.lastXWidth) / 2;
68
+ const newXStart = this.lastXStart - delta;
69
+ const newXEnd = this.lastXEnd + delta;
70
+ if (this.lastXStart !== newXStart || this.lastXEnd !== newXEnd) {
71
+ this.scale.setXScale(newXStart, newXEnd);
72
+ }
73
+ }
45
74
  };
46
75
  this.onXDragEnd = () => {
47
76
  // Continue redrawing hit test
@@ -3,7 +3,7 @@
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 { CanvasElement } from '../../canvas/canvas-bounds-container';
6
+ import { CanvasElement, X_AXIS_MOBILE_PADDING } from '../../canvas/canvas-bounds-container';
7
7
  import { calculateTextWidth } from '../../utils/canvas/canvas-font-measure-tool.utils';
8
8
  /**
9
9
  * This Drawer draws regular time labels for X Axis.
@@ -38,7 +38,7 @@ export class XAxisTimeLabelsDrawer {
38
38
  ctx.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
39
39
  const color = this.config.colors.xAxis.labelTextColor;
40
40
  const labels = this.labelsProvider();
41
- this.drawLabels(ctx, labels, bounds, color, fontHeight, fontFamily, offsetTop);
41
+ this.drawLabels(ctx, labels, bounds, color, fontHeight, fontFamily, offsetTop + X_AXIS_MOBILE_PADDING / 2);
42
42
  ctx.restore();
43
43
  }
44
44
  }
@@ -60,7 +60,8 @@ export declare class FancyYAxisLabelsModel extends ChartBaseElement {
60
60
  * an easier way to manage custom y-axis labels, than y-axis labels providers, but doesn't support overlapping avoidance
61
61
  */
62
62
  readonly customLabels: Record<string, VisualYAxisLabel>;
63
- private labelsProviders;
63
+ private _labelsProviders;
64
+ get labelsProviders(): Record<string, Record<string, YAxisLabelsProvider>>;
64
65
  private labelsPositionRecalculatedSubject;
65
66
  private animFrameId;
66
67
  constructor(eventBus: EventBus, scale: ScaleModel, canvasBoundsContainer: CanvasBoundsContainer, state: YAxisConfig, canvasModel: CanvasModel, paneUUID: string, updateYAxisWidth: () => void, chartResizeHandler: ChartResizeHandler);
@@ -157,4 +158,5 @@ export declare class FancyYAxisLabelsModel extends ChartBaseElement {
157
158
  */
158
159
  export interface YAxisLabelsProvider {
159
160
  readonly getUnorderedLabels: () => LabelGroup[];
161
+ yAxisBoundsProvider?: () => Bounds;
160
162
  }
@@ -27,6 +27,9 @@ export const LabelsGroups = {
27
27
  * Anything but the base labels which are generated in other component {@link YAxisBaseLabelsModel}
28
28
  */
29
29
  export class FancyYAxisLabelsModel extends ChartBaseElement {
30
+ get labelsProviders() {
31
+ return this._labelsProviders;
32
+ }
30
33
  constructor(eventBus, scale, canvasBoundsContainer, state, canvasModel, paneUUID, updateYAxisWidth, chartResizeHandler) {
31
34
  super();
32
35
  this.eventBus = eventBus;
@@ -42,7 +45,7 @@ export class FancyYAxisLabelsModel extends ChartBaseElement {
42
45
  * an easier way to manage custom y-axis labels, than y-axis labels providers, but doesn't support overlapping avoidance
43
46
  */
44
47
  this.customLabels = {};
45
- this.labelsProviders = {};
48
+ this._labelsProviders = {};
46
49
  this.labelsPositionRecalculatedSubject = new Subject();
47
50
  this.animFrameId = `anim_cache_${uuid()}`;
48
51
  this.initModel();