@devexperts/dxcharts-lite 2.6.0 → 2.6.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 (30) hide show
  1. package/dist/chart/bootstrap.js +1 -1
  2. package/dist/chart/canvas/canvas-bounds-container.d.ts +1 -0
  3. package/dist/chart/canvas/canvas-bounds-container.js +4 -1
  4. package/dist/chart/chart.config.d.ts +8 -0
  5. package/dist/chart/chart.config.js +2 -1
  6. package/dist/chart/components/cross_tool/cross-tool.component.js +2 -2
  7. package/dist/chart/components/cross_tool/cross-tool.drawer.d.ts +3 -1
  8. package/dist/chart/components/cross_tool/cross-tool.drawer.js +4 -3
  9. package/dist/chart/components/cross_tool/cross-tool.model.d.ts +6 -6
  10. package/dist/chart/components/cross_tool/cross-tool.model.js +42 -11
  11. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +3 -3
  12. package/dist/chart/components/high_low/high-low.drawer.js +1 -1
  13. package/dist/chart/components/pane/pane-manager.component.d.ts +5 -0
  14. package/dist/chart/components/pane/pane-manager.component.js +20 -0
  15. package/dist/chart/components/pane/pane.component.d.ts +9 -1
  16. package/dist/chart/components/pane/pane.component.js +16 -0
  17. package/dist/chart/components/x_axis/x-axis-draw.functions.js +2 -2
  18. package/dist/chart/components/x_axis/x-axis-scale.handler.d.ts +1 -0
  19. package/dist/chart/components/x_axis/x-axis-scale.handler.js +37 -8
  20. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +2 -2
  21. package/dist/chart/inputhandlers/cross-event-producer.component.d.ts +22 -0
  22. package/dist/chart/inputhandlers/cross-event-producer.component.js +11 -1
  23. package/dist/chart/inputhandlers/hover-producer.component.d.ts +5 -3
  24. package/dist/chart/inputhandlers/hover-producer.component.js +70 -16
  25. package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +10 -0
  26. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +18 -0
  27. package/dist/chart/inputlisteners/canvas-input-listener.component.js +2 -7
  28. package/dist/chart/model/candle-series.model.js +1 -1
  29. package/dist/dxchart.min.js +4 -4
  30. package/package.json +1 -1
@@ -182,7 +182,7 @@ export default class ChartBootstrap {
182
182
  // grid component
183
183
  const verticalGridComponent = new GridComponent(mainCanvasModel, scaleModel, config, this.yAxisComponent.state, 'GRID', drawingManager, () => this.canvasBoundsContainer.getBounds(CanvasElement.ALL_PANES), () => this.canvasBoundsContainer.getBounds(chartPaneId), () => this.xAxisComponent.xAxisLabelsGenerator.labels, () => [], undefined, () => config.components.grid.visible);
184
184
  this.chartComponents.push(verticalGridComponent);
185
- this.hoverProducer = new HoverProducerComponent(this.crossEventProducer, scaleModel, config, chartModel, canvasInputListener, this.canvasBoundsContainer, this.paneManager, timeZoneModel, formatterFactory);
185
+ this.hoverProducer = new HoverProducerComponent(this.crossEventProducer, scaleModel, config, chartModel, canvasInputListener, this.canvasBoundsContainer, this.paneManager, timeZoneModel, chartPanComponent.mainCanvasTouchHandler, formatterFactory);
186
186
  this.chartComponents.push(this.hoverProducer);
187
187
  this.crossToolComponent = new CrossToolComponent(config, crossToolCanvasModel, canvasBoundsContainer, drawingManager, paneManager, this.crossEventProducer, this.hoverProducer);
188
188
  this.chartComponents.push(this.crossToolComponent);
@@ -45,6 +45,7 @@ export declare class CanvasElement {
45
45
  }
46
46
  export declare const DEFAULT_BOUNDS: Bounds;
47
47
  export declare const DEFAULT_MIN_PANE_HEIGHT = 20;
48
+ export declare const X_AXIS_MOBILE_PADDING: number;
48
49
  /**
49
50
  * This component listens EVENT_DRAW and recalculates bounds of canvas chart elements.
50
51
  * {@link getBounds} method will always give actual placement of element you want.
@@ -45,6 +45,8 @@ const N_MAP_H = 35;
45
45
  const N_MAP_BUTTON_W = 15;
46
46
  const KNOTS_W_MOBILE_MULTIPLIER = 1.5;
47
47
  const N_MAP_KNOT_W = isMobile() ? 8 * KNOTS_W_MOBILE_MULTIPLIER : 8;
48
+ // additional x axis height padding for mobiles, used for better usability on mobile devices
49
+ export const X_AXIS_MOBILE_PADDING = isMobile() ? 5 : 0;
48
50
  /**
49
51
  * we need to check that: heightRatios - 1 < 0.000001 after calculations between decimals
50
52
  */
@@ -390,7 +392,8 @@ export class CanvasBoundsContainer {
390
392
  this.xAxisHeight =
391
393
  fontHeight +
392
394
  ((_a = this.config.components.xAxis.padding.top) !== null && _a !== void 0 ? _a : 0) +
393
- ((_b = this.config.components.xAxis.padding.bottom) !== null && _b !== void 0 ? _b : 0);
395
+ ((_b = this.config.components.xAxis.padding.bottom) !== null && _b !== void 0 ? _b : 0) +
396
+ X_AXIS_MOBILE_PADDING;
394
397
  }
395
398
  return this.xAxisHeight;
396
399
  }
@@ -322,6 +322,10 @@ export interface ChartConfigComponentsChart {
322
322
  selectedWidth: number;
323
323
  minCandlesOffset: number;
324
324
  histogram: ChartConfigComponentsHistogram;
325
+ /**
326
+ * The maximum amount of Y axis scales on a single chart
327
+ */
328
+ maxYAxisScalesAmount: number;
325
329
  sortCandles?: (candles: Candle[]) => Candle[];
326
330
  }
327
331
  export interface ChartConfigComponentsEvents {
@@ -482,6 +486,10 @@ export interface ChartConfigComponentsHighLow {
482
486
  * Font config of high/low labels.
483
487
  */
484
488
  font: string;
489
+ prefix: {
490
+ high: string;
491
+ low: string;
492
+ };
485
493
  }
486
494
  export interface ChartConfigComponentsCrossTool {
487
495
  /**
@@ -71,6 +71,7 @@ export const getDefaultConfig = () => ({
71
71
  histogram: {
72
72
  barCapSize: 1,
73
73
  },
74
+ maxYAxisScalesAmount: 10,
74
75
  sortCandles: defaultSortCandles,
75
76
  },
76
77
  yAxis: {
@@ -192,7 +193,7 @@ export const getDefaultConfig = () => ({
192
193
  logoWidth: 20,
193
194
  logoHeight: 20,
194
195
  },
195
- highLow: { visible: false, font: '12px sans-serif' },
196
+ highLow: { visible: false, font: '12px sans-serif', prefix: { high: 'H: ', low: 'L: ' } },
196
197
  highlights: {
197
198
  visible: false,
198
199
  fontFamily: 'Open Sans',
@@ -22,11 +22,11 @@ export class CrossToolComponent extends ChartBaseElement {
22
22
  this.drawingManager = drawingManager;
23
23
  this.paneManager = paneManager;
24
24
  this.crossToolTypeDrawers = {};
25
- this.model = new CrossToolModel(config.components.crossTool, this.crossToolCanvasModel, crossEventProducer, hoverProducer);
25
+ this.model = new CrossToolModel(config.components.crossTool, this.crossToolCanvasModel, crossEventProducer, hoverProducer, this.canvasBoundsContainer);
26
26
  this.addChildEntity(this.model);
27
27
  const clearCanvasDrawer = new ClearCanvasDrawer(this.crossToolCanvasModel);
28
28
  this.registerDefaultDrawerTypes();
29
- const crossToolDrawer = new CrossToolDrawer(this.model, this.crossToolCanvasModel, this.crossToolTypeDrawers);
29
+ const crossToolDrawer = new CrossToolDrawer(this.model, this.config, this.crossToolCanvasModel, this.crossToolTypeDrawers);
30
30
  const compositeDrawer = new CompositeDrawer();
31
31
  compositeDrawer.addDrawer(clearCanvasDrawer, 'CLEAR_CANVAS');
32
32
  compositeDrawer.addDrawer(crossToolDrawer, 'CROSS_TOOL_DRAWER');
@@ -6,14 +6,16 @@
6
6
  import { CanvasModel } from '../../model/canvas.model';
7
7
  import { Drawer } from '../../drawers/drawing-manager';
8
8
  import { CrossToolHover, CrossToolModel, CrossToolType } from './cross-tool.model';
9
+ import { FullChartConfig } from '../../chart.config';
9
10
  export interface CrossToolTypeDrawer {
10
11
  draw: (ctx: CanvasRenderingContext2D, hover: CrossToolHover) => void;
11
12
  }
12
13
  export declare class CrossToolDrawer implements Drawer {
13
14
  private model;
15
+ private config;
14
16
  private crossToolCanvasModel;
15
17
  private readonly crossToolTypeDrawers;
16
- constructor(model: CrossToolModel, crossToolCanvasModel: CanvasModel, crossToolTypeDrawers: Record<CrossToolType, CrossToolTypeDrawer>);
18
+ constructor(model: CrossToolModel, config: FullChartConfig, crossToolCanvasModel: CanvasModel, crossToolTypeDrawers: Record<CrossToolType, CrossToolTypeDrawer>);
17
19
  /**
18
20
  * Draws the cross tool on the canvas.
19
21
  * @function
@@ -4,8 +4,9 @@
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
  export class CrossToolDrawer {
7
- constructor(model, crossToolCanvasModel, crossToolTypeDrawers) {
7
+ constructor(model, config, crossToolCanvasModel, crossToolTypeDrawers) {
8
8
  this.model = model;
9
+ this.config = config;
9
10
  this.crossToolCanvasModel = crossToolCanvasModel;
10
11
  this.crossToolTypeDrawers = crossToolTypeDrawers;
11
12
  }
@@ -18,12 +19,12 @@ export class CrossToolDrawer {
18
19
  * @returns {void}
19
20
  */
20
21
  draw() {
21
- const drawer = this.crossToolTypeDrawers[this.model.type];
22
+ const drawer = this.crossToolTypeDrawers[this.config.components.crossTool.type];
22
23
  if (drawer) {
23
24
  this.model.currentHover && drawer.draw(this.crossToolCanvasModel.ctx, this.model.currentHover);
24
25
  }
25
26
  else {
26
- console.error(`No cross tool drawer type registered for drawer type ${this.model.type}`);
27
+ console.error(`No cross tool drawer type registered for drawer type ${this.config.components.crossTool.type}`);
27
28
  }
28
29
  }
29
30
  /**
@@ -9,6 +9,7 @@ import { CrossEventProducerComponent } from '../../inputhandlers/cross-event-pro
9
9
  import { Hover, HoverProducerComponent } from '../../inputhandlers/hover-producer.component';
10
10
  import { CanvasModel } from '../../model/canvas.model';
11
11
  import { ChartBaseElement } from '../../model/chart-base-element';
12
+ import { CanvasBoundsContainer } from '../../canvas/canvas-bounds-container';
12
13
  export type CrossToolType = 'cross-and-labels' | 'only-labels' | 'none' | string;
13
14
  export interface CrossToolHover {
14
15
  x: number;
@@ -21,11 +22,11 @@ export declare class CrossToolModel extends ChartBaseElement {
21
22
  private crossToolCanvasModel;
22
23
  private crossEventProducer;
23
24
  private hoverProducer;
25
+ private canvasBoundsContainer;
24
26
  currentHoverSubject: BehaviorSubject<CrossToolHover | null>;
25
27
  get currentHover(): CrossToolHover | null;
26
28
  set currentHover(value: CrossToolHover | null);
27
- type: CrossToolType;
28
- constructor(config: Required<ChartConfigComponentsCrossTool>, crossToolCanvasModel: CanvasModel, crossEventProducer: CrossEventProducerComponent, hoverProducer: HoverProducerComponent);
29
+ constructor(config: Required<ChartConfigComponentsCrossTool>, crossToolCanvasModel: CanvasModel, crossEventProducer: CrossEventProducerComponent, hoverProducer: HoverProducerComponent, canvasBoundsContainer: CanvasBoundsContainer);
29
30
  /**
30
31
  * Sets the type of the CrossTool object.
31
32
  *
@@ -35,9 +36,7 @@ export declare class CrossToolModel extends ChartBaseElement {
35
36
  setType(type: CrossToolType): void;
36
37
  /**
37
38
  * Method to activate the cross tool.
38
- * It subscribes to the canvasInputListener's mouse move event and fires the draw event.
39
- * It also subscribes to the eventBus's hover and close hover events and updates the hover and fires the draw event accordingly.
40
- * It also subscribes to the chartModel's candlesSetSubject and timeZoneModel's observeTimeZoneChanged events and recalculates the cross tool X formatter.
39
+ * It subscribes to the hoverProducer's hover event and updates the crosstool.
41
40
  */
42
41
  protected doActivate(): void;
43
42
  /**
@@ -59,5 +58,6 @@ export declare class CrossToolModel extends ChartBaseElement {
59
58
  * @param {number} hover.candleHover.closestOHLCY - The y coordinate of the closest OHLC price of the candle.
60
59
  * @returns {void}
61
60
  */
62
- updateHover(hover: Hover, magnetTarget?: import("./cross-tool.component").MagnetTarget): void;
61
+ updateCrossTool(hover: Hover, magnetTarget?: import("./cross-tool.component").MagnetTarget): void;
62
+ private updateCrossToolMobile;
63
63
  }
@@ -5,7 +5,8 @@
5
5
  */
6
6
  import { BehaviorSubject } from 'rxjs';
7
7
  import { ChartBaseElement } from '../../model/chart-base-element';
8
- import { CHART_UUID } from '../../canvas/canvas-bounds-container';
8
+ import { CanvasElement, CHART_UUID } from '../../canvas/canvas-bounds-container';
9
+ import { isMobile } from '../../utils/device/browser.utils';
9
10
  export class CrossToolModel extends ChartBaseElement {
10
11
  get currentHover() {
11
12
  return this.currentHoverSubject.getValue();
@@ -13,16 +14,15 @@ export class CrossToolModel extends ChartBaseElement {
13
14
  set currentHover(value) {
14
15
  this.currentHoverSubject.next(value);
15
16
  }
16
- constructor(config, crossToolCanvasModel, crossEventProducer, hoverProducer) {
17
+ constructor(config, crossToolCanvasModel, crossEventProducer, hoverProducer, canvasBoundsContainer) {
17
18
  super();
18
19
  this.config = config;
19
20
  this.crossToolCanvasModel = crossToolCanvasModel;
20
21
  this.crossEventProducer = crossEventProducer;
21
22
  this.hoverProducer = hoverProducer;
23
+ this.canvasBoundsContainer = canvasBoundsContainer;
22
24
  // the main hover object which will be presented on UI
23
25
  this.currentHoverSubject = new BehaviorSubject(null);
24
- this.type = 'cross-and-labels';
25
- this.type = config.type;
26
26
  }
27
27
  /**
28
28
  * Sets the type of the CrossTool object.
@@ -31,19 +31,17 @@ export class CrossToolModel extends ChartBaseElement {
31
31
  * @returns {void}
32
32
  */
33
33
  setType(type) {
34
- this.type = type;
34
+ this.config.type = type;
35
35
  }
36
36
  /**
37
37
  * Method to activate the cross tool.
38
- * It subscribes to the canvasInputListener's mouse move event and fires the draw event.
39
- * It also subscribes to the eventBus's hover and close hover events and updates the hover and fires the draw event accordingly.
40
- * It also subscribes to the chartModel's candlesSetSubject and timeZoneModel's observeTimeZoneChanged events and recalculates the cross tool X formatter.
38
+ * It subscribes to the hoverProducer's hover event and updates the crosstool.
41
39
  */
42
40
  doActivate() {
43
41
  super.doActivate();
44
42
  this.addRxSubscription(this.hoverProducer.hoverSubject.subscribe(hover => {
45
43
  if (this.crossEventProducer.crossSubject.getValue() !== null && hover !== null) {
46
- this.updateHover(hover);
44
+ isMobile() ? this.updateCrossToolMobile(hover) : this.updateCrossTool(hover);
47
45
  }
48
46
  else {
49
47
  this.currentHover = null;
@@ -56,7 +54,7 @@ export class CrossToolModel extends ChartBaseElement {
56
54
  * @private
57
55
  */
58
56
  fireDraw() {
59
- if (this.type !== 'none') {
57
+ if (this.config.type !== 'none') {
60
58
  this.crossToolCanvasModel.fireDraw();
61
59
  }
62
60
  }
@@ -74,7 +72,7 @@ export class CrossToolModel extends ChartBaseElement {
74
72
  * @param {number} hover.candleHover.closestOHLCY - The y coordinate of the closest OHLC price of the candle.
75
73
  * @returns {void}
76
74
  */
77
- updateHover(hover, magnetTarget = this.config.magnetTarget) {
75
+ updateCrossTool(hover, magnetTarget = this.config.magnetTarget) {
78
76
  if (this.currentHover === null) {
79
77
  this.currentHover = { x: hover.x, y: 0, time: hover.timeFormatted, paneId: hover.paneId };
80
78
  }
@@ -110,4 +108,37 @@ export class CrossToolModel extends ChartBaseElement {
110
108
  this.currentHover.paneId = hover.paneId;
111
109
  this.currentHoverSubject.next(this.currentHover);
112
110
  }
111
+ updateCrossToolMobile(hover) {
112
+ var _a;
113
+ // mobile crosstool works only after long touch event
114
+ if (!this.hoverProducer.longTouchActivatedSubject.getValue()) {
115
+ return;
116
+ }
117
+ const { fixed, temp, isSet } = this.crossEventProducer.crossToolTouchInfo;
118
+ // long touch makes crosstool fixed and the further moving will place crosstool under the current hover coordinates (ordinary logic)
119
+ // if crosstool is already set (long touch end event happened) the moving of chart will move crosstool according to it's initial (fixed position)
120
+ if (!isSet) {
121
+ this.updateCrossTool(hover);
122
+ return;
123
+ }
124
+ // additional crosstool move logic
125
+ const paneBounds = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID(hover.paneId));
126
+ const offset = 5;
127
+ // take a difference inbetween current hover and temporary crosstool coordinates
128
+ const xDiff = hover.x - temp.x;
129
+ const yDiff = hover.y - temp.y;
130
+ // apply the difference to the fixed coordinates
131
+ const rawX = fixed.x + xDiff;
132
+ const rawY = fixed.y + yDiff;
133
+ const paneYStart = paneBounds.y + offset;
134
+ const paneYEnd = paneBounds.y + paneBounds.height - offset;
135
+ // check for chart bounds and don't move crosstool outside of it
136
+ const x = rawX < offset ? offset : rawX > paneBounds.width - offset ? paneBounds.width - offset : rawX;
137
+ const y = rawY < paneYStart ? paneYStart : rawY > paneYEnd ? paneYEnd : rawY;
138
+ const crossToolHover = (_a = this.hoverProducer.createHover(x, y, hover.paneId)) !== null && _a !== void 0 ? _a : hover;
139
+ const updatedHover = Object.assign(Object.assign({}, crossToolHover), { x,
140
+ y });
141
+ this.crossEventProducer.crossToolHover = updatedHover;
142
+ this.updateCrossTool(updatedHover);
143
+ }
113
144
  }
@@ -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 { avoidAntialiasing, drawRoundedRect } from '../../../utils/canvas/canvas-drawing-functions.utils';
8
8
  import { priceLabelDrawersMap } from '../../y_axis/price_labels/price-label.drawer';
9
9
  export class CrossAndLabelsDrawerType {
@@ -98,12 +98,12 @@ export class CrossAndLabelsDrawerType {
98
98
  const boxWidth = width + xLabelPaddingLeft + xLabelPaddingRight;
99
99
  const boxHeight = fontHeight + xLabelPaddingTop + xLabelPaddingBottom;
100
100
  const xBoxPos = Math.max(x - boxWidth / 2, 0);
101
- const yBoxPos = xAxis.y + xLabelMarginTop;
101
+ const yBoxPos = xAxis.y + xLabelMarginTop + X_AXIS_MOBILE_PADDING / 2;
102
102
  drawRoundedRect(ctx, xBoxPos, yBoxPos, boxWidth, boxHeight);
103
103
  // label
104
104
  ctx.fillStyle = crossToolColors.labelTextColor;
105
105
  const xTextPos = Math.max(x - width / 2, xLabelPaddingLeft);
106
- const yTextPos = xAxis.y + xLabelMarginTop + fontHeight + xLabelPaddingTop - 1; // -1 for vertical adjustment
106
+ const yTextPos = xAxis.y + xLabelMarginTop + fontHeight + X_AXIS_MOBILE_PADDING / 2 + xLabelPaddingTop - 1; // -1 for vertical adjustment
107
107
  ctx.fillText(labelText, xTextPos, yTextPos);
108
108
  ctx.restore();
109
109
  }
@@ -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;
@@ -107,6 +108,10 @@ export declare class PaneManager extends ChartBaseElement {
107
108
  * Shows a pane, use if the pane is hidden
108
109
  */
109
110
  showPane(paneUUID: string): void;
111
+ /**
112
+ * Move data series to a certain pane, or create a new one if no pane is found
113
+ */
114
+ moveDataSeriesToPane(dataSeries: DataSeriesModel[], initialPane: PaneComponent, initialExtent: YExtentComponent, paneUUID?: string, extent?: YExtentComponent, direction?: MoveDataSeriesToPaneDirection): void;
110
115
  /**
111
116
  * Adds cursors to the chart elements based on the provided uuid and cursor type.
112
117
  * @private
@@ -188,6 +188,26 @@ export class PaneManager extends ChartBaseElement {
188
188
  this.canvasBoundsContainer.showPaneBounds(paneUUID);
189
189
  this.recalculateState();
190
190
  }
191
+ /**
192
+ * Move data series to a certain pane, or create a new one if no pane is found
193
+ */
194
+ moveDataSeriesToPane(dataSeries, initialPane, initialExtent, paneUUID, extent, direction) {
195
+ const pane = paneUUID && this.panes[paneUUID];
196
+ if (!pane) {
197
+ const order = direction && direction === 'above' ? 0 : this.panesOrder.length;
198
+ const newPane = this.createPane(undefined, { order });
199
+ newPane.moveDataSeriesToExistingExtentComponent(dataSeries, initialPane, initialExtent, newPane.mainExtent);
200
+ initialPane.yExtentComponents.length === 0 && this.removePane(initialPane.uuid);
201
+ return;
202
+ }
203
+ if (extent) {
204
+ pane.moveDataSeriesToExistingExtentComponent(dataSeries, initialPane, initialExtent, extent);
205
+ }
206
+ else {
207
+ pane.moveDataSeriesToNewExtentComponent(dataSeries, initialPane, initialExtent);
208
+ }
209
+ initialPane.yExtentComponents.length === 0 && this.removePane(initialPane.uuid);
210
+ }
191
211
  /**
192
212
  * Adds cursors to the chart elements based on the provided uuid and cursor type.
193
213
  * @private
@@ -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';
@@ -84,6 +84,14 @@ export declare class PaneComponent extends ChartBaseElement {
84
84
  private addCursors;
85
85
  createExtentComponent(options?: AtLeastOne<YExtentCreationOptions>): YExtentComponent;
86
86
  removeExtentComponent(extentComponent: YExtentComponent): void;
87
+ /**
88
+ * Create new pane extent and attach data series to it
89
+ */
90
+ moveDataSeriesToNewExtentComponent(dataSeries: DataSeriesModel[], initialPane: PaneComponent, initialExtent: YExtentComponent, align?: YAxisAlign): void;
91
+ /**
92
+ * Attach data series to existing y axis extent
93
+ */
94
+ moveDataSeriesToExistingExtentComponent(dataSeries: DataSeriesModel[], initialPane: PaneComponent, initialExtent: YExtentComponent, extentComponent: YExtentComponent): void;
87
95
  /**
88
96
  * This method updates the view by calling the doAutoScale method of the scaleModel and firing the Draw event using the eventBus.
89
97
  * @private
@@ -149,6 +149,22 @@ export class PaneComponent extends ChartBaseElement {
149
149
  this.yExtentComponents.forEach((c, idx) => (c.idx = idx));
150
150
  this.canvasBoundsContainer.updateYAxisWidths();
151
151
  }
152
+ /**
153
+ * Create new pane extent and attach data series to it
154
+ */
155
+ moveDataSeriesToNewExtentComponent(dataSeries, initialPane, initialExtent, align = 'right') {
156
+ const extent = this.createExtentComponent();
157
+ extent.yAxis.setYAxisAlign(align);
158
+ dataSeries.forEach(series => series.moveToExtent(extent));
159
+ initialExtent.dataSeries.size === 0 && initialPane.removeExtentComponent(initialExtent);
160
+ }
161
+ /**
162
+ * Attach data series to existing y axis extent
163
+ */
164
+ moveDataSeriesToExistingExtentComponent(dataSeries, initialPane, initialExtent, extentComponent) {
165
+ dataSeries.forEach(series => series.moveToExtent(extentComponent));
166
+ initialExtent.dataSeries.size === 0 && initialPane.removeExtentComponent(initialExtent);
167
+ }
152
168
  /**
153
169
  * This method updates the view by calling the doAutoScale method of the scaleModel and firing the Draw event using the eventBus.
154
170
  * @private
@@ -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
  }
@@ -8,15 +8,36 @@ import { CanvasBoundsContainer, HitBoundsTest, HitBoundsTestOptionsPartial } fro
8
8
  import { CanvasInputListenerComponent } from '../inputlisteners/canvas-input-listener.component';
9
9
  import { ChartBaseElement } from '../model/chart-base-element';
10
10
  import { Unsubscriber } from '../utils/function.utils';
11
+ import { Pixel } from '../model/scaling/viewport.model';
12
+ import { Hover } from './hover-producer.component';
11
13
  /**
12
14
  * [x, y, uuid - Unique identifier for the subscription]
13
15
  */
14
16
  export type CrossEvent = [number, number, string];
17
+ interface CrossToolTouchInfo {
18
+ fixed: {
19
+ x: Pixel;
20
+ y: Pixel;
21
+ };
22
+ temp: {
23
+ x: Pixel;
24
+ y: Pixel;
25
+ };
26
+ isSet: boolean;
27
+ /**
28
+ * additional flag to determine ordinary and long taps
29
+ * crosstool shouldn't be hidden after longtouch event even if coordinates are the same
30
+ * becomes true after touchStart and false after longTouchStart
31
+ */
32
+ isCommonTap: boolean;
33
+ }
15
34
  export declare class CrossEventProducerComponent extends ChartBaseElement {
16
35
  private canvasInputListener;
17
36
  private canvasBoundsContainer;
18
37
  panesSubscriptions: Partial<Record<string, Subscription>>;
19
38
  crossSubject: BehaviorSubject<CrossEvent | null>;
39
+ crossToolHover: Hover | null;
40
+ crossToolTouchInfo: CrossToolTouchInfo;
20
41
  constructor(canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer);
21
42
  protected doActivate(): void;
22
43
  /**
@@ -45,3 +66,4 @@ export declare class CrossEventProducerComponent extends ChartBaseElement {
45
66
  */
46
67
  subscribeMouseOverHT(uuid: string, hitTest: HitBoundsTest): Unsubscriber;
47
68
  }
69
+ export {};
@@ -6,6 +6,7 @@
6
6
  import { BehaviorSubject, combineLatest } from 'rxjs';
7
7
  import { filter } from 'rxjs/operators';
8
8
  import { ChartBaseElement } from '../model/chart-base-element';
9
+ import { isMobile } from '../utils/device/browser.utils';
9
10
  export class CrossEventProducerComponent extends ChartBaseElement {
10
11
  constructor(canvasInputListener, canvasBoundsContainer) {
11
12
  super();
@@ -13,6 +14,14 @@ export class CrossEventProducerComponent extends ChartBaseElement {
13
14
  this.canvasBoundsContainer = canvasBoundsContainer;
14
15
  this.panesSubscriptions = {};
15
16
  this.crossSubject = new BehaviorSubject(null);
17
+ // mobile specific crosstool hover and touch info
18
+ this.crossToolHover = null;
19
+ this.crossToolTouchInfo = {
20
+ fixed: { x: 0, y: 0 },
21
+ temp: { x: 0, y: 0 },
22
+ isSet: false,
23
+ isCommonTap: false,
24
+ };
16
25
  }
17
26
  doActivate() {
18
27
  super.doActivate();
@@ -62,7 +71,8 @@ export class CrossEventProducerComponent extends ChartBaseElement {
62
71
  this.crossSubject.next(cross);
63
72
  closeHoverFired = false;
64
73
  }
65
- else {
74
+ // crosstool should be hidden if hovering nonpane only on desktop
75
+ if (!enter && !isMobile()) {
66
76
  this.crossSubject.next(null);
67
77
  closeHoverFired = true;
68
78
  }