@devexperts/dxcharts-lite 2.5.8 → 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.
- package/dist/chart/__tests__/chart.test.js +5 -5
- package/dist/chart/__tests__/env.js +1 -1
- package/dist/chart/bootstrap.js +1 -1
- package/dist/chart/canvas/canvas-bounds-container.d.ts +1 -0
- package/dist/chart/canvas/canvas-bounds-container.js +28 -4
- package/dist/chart/chart.config.d.ts +10 -0
- package/dist/chart/chart.config.js +4 -2
- package/dist/chart/components/chart/candle-transformer.functions.js +1 -1
- package/dist/chart/components/chart/candle.functions.d.ts +1 -1
- package/dist/chart/components/chart/candle.functions.js +3 -2
- package/dist/chart/components/chart/chart.component.d.ts +29 -8
- package/dist/chart/components/chart/chart.component.js +33 -4
- package/dist/chart/components/chart/chart.model.d.ts +41 -4
- package/dist/chart/components/chart/chart.model.js +90 -16
- package/dist/chart/components/chart/fake-candles.js +2 -0
- package/dist/chart/components/chart/fake-visual-candle.d.ts +4 -4
- package/dist/chart/components/chart/fake-visual-candle.js +4 -4
- package/dist/chart/components/cross_tool/cross-tool.component.js +2 -2
- package/dist/chart/components/cross_tool/cross-tool.drawer.d.ts +3 -1
- package/dist/chart/components/cross_tool/cross-tool.drawer.js +4 -3
- package/dist/chart/components/cross_tool/cross-tool.model.d.ts +6 -6
- package/dist/chart/components/cross_tool/cross-tool.model.js +42 -11
- package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +3 -3
- package/dist/chart/components/high_low/high-low.drawer.js +1 -1
- package/dist/chart/components/pane/pane-manager.component.d.ts +5 -0
- package/dist/chart/components/pane/pane-manager.component.js +20 -0
- package/dist/chart/components/pane/pane.component.d.ts +9 -1
- package/dist/chart/components/pane/pane.component.js +16 -0
- package/dist/chart/components/volumes/separate-volumes.component.d.ts +1 -3
- package/dist/chart/components/volumes/separate-volumes.component.js +1 -3
- package/dist/chart/components/volumes/volumes.component.js +1 -1
- package/dist/chart/components/volumes/volumes.drawer.js +3 -3
- package/dist/chart/components/watermark/water-mark.component.d.ts +3 -12
- package/dist/chart/components/watermark/water-mark.component.js +1 -1
- package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.js +1 -1
- package/dist/chart/components/x_axis/x-axis-draw.functions.js +2 -2
- package/dist/chart/components/x_axis/x-axis-scale.handler.d.ts +1 -0
- package/dist/chart/components/x_axis/x-axis-scale.handler.js +39 -10
- package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +2 -2
- package/dist/chart/components/x_axis/x-axis.component.js +1 -1
- package/dist/chart/components/y_axis/y-axis-scale.handler.js +3 -3
- package/dist/chart/drawers/drawing-manager.d.ts +1 -1
- package/dist/chart/drawers/drawing-manager.js +0 -1
- package/dist/chart/inputhandlers/cross-event-producer.component.d.ts +22 -0
- package/dist/chart/inputhandlers/cross-event-producer.component.js +11 -1
- package/dist/chart/inputhandlers/hover-producer.component.d.ts +5 -3
- package/dist/chart/inputhandlers/hover-producer.component.js +78 -18
- package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +10 -0
- package/dist/chart/inputhandlers/main-canvas-touch.handler.js +18 -0
- package/dist/chart/inputlisteners/canvas-input-listener.component.js +2 -7
- package/dist/chart/model/candle-series.model.js +1 -1
- package/dist/chart/model/candle.model.d.ts +3 -0
- package/dist/chart/model/candle.model.js +7 -1
- package/dist/chart/model/data-series.model.d.ts +3 -3
- package/dist/chart/model/data-series.model.js +1 -1
- package/dist/chart/model/scale.model.js +1 -1
- package/dist/chart/model/scaling/viewport.model.d.ts +2 -1
- package/dist/chart/model/scaling/viewport.model.js +6 -1
- package/dist/chart/model/time-zone.model.js +1 -3
- package/dist/chart/utils/candles-generator-ts.utils.d.ts +1 -0
- package/dist/chart/utils/candles-generator.utils.d.ts +1 -0
- package/dist/chart/utils/candles-generator.utils.js +2 -0
- package/dist/chart/utils/string.utils.d.ts +6 -0
- package/dist/chart/utils/string.utils.js +19 -0
- package/dist/chart/utils/types.utils.d.ts +9 -0
- package/dist/chart/utils/types.utils.js +6 -0
- package/dist/dxchart.min.js +4 -4
- package/package.json +1 -1
|
@@ -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
|
}
|
|
@@ -82,7 +82,7 @@ export class XAxisComponent extends ChartBaseElement {
|
|
|
82
82
|
this.xAxisLabelsGenerator.recalculateLabels();
|
|
83
83
|
}));
|
|
84
84
|
this.addRxSubscription(this.chartComponent.chartModel.candlesUpdatedSubject
|
|
85
|
-
.pipe(map(() => lastOf(this.chartComponent.chartModel.mainCandleSeries.visualPoints)), distinctUntilChanged((a, b) => { var _a, _b; return ((_a = a === null || a === void 0 ? void 0 : a.candle) === null || _a === void 0 ? void 0 : _a.
|
|
85
|
+
.pipe(map(() => lastOf(this.chartComponent.chartModel.mainCandleSeries.visualPoints)), distinctUntilChanged((a, b) => { var _a, _b; return ((_a = a === null || a === void 0 ? void 0 : a.candle) === null || _a === void 0 ? void 0 : _a.id) === ((_b = b === null || b === void 0 ? void 0 : b.candle) === null || _b === void 0 ? void 0 : _b.id); }), filter(notEmpty))
|
|
86
86
|
.subscribe(x => { var _a, _b; return (_b = (_a = this.xAxisLabelsGenerator) === null || _a === void 0 ? void 0 : _a.updateLastLabel) === null || _b === void 0 ? void 0 : _b.call(_a, x); }));
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
@@ -4,7 +4,7 @@
|
|
|
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 { Subject } from 'rxjs';
|
|
7
|
-
import { CanvasElement, DEFAULT_MIN_PANE_HEIGHT } from '../../canvas/canvas-bounds-container';
|
|
7
|
+
import { CanvasElement, DEFAULT_MIN_PANE_HEIGHT, } from '../../canvas/canvas-bounds-container';
|
|
8
8
|
import { ChartBaseElement } from '../../model/chart-base-element';
|
|
9
9
|
import { DragNDropYComponent } from '../dran-n-drop_helper/drag-n-drop-y.component';
|
|
10
10
|
// if you drag full Y height from top to bottom - you will have x3 zoom, and vice-versa
|
|
@@ -73,8 +73,8 @@ export class YAxisScaleHandler extends ChartBaseElement {
|
|
|
73
73
|
// Continue redrawing hit test
|
|
74
74
|
this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(true);
|
|
75
75
|
};
|
|
76
|
-
this.setDblTapCallback = (cb) => this.dblTapCallback = cb;
|
|
77
|
-
this.setDblClickCallback = (cb) => this.dblClickCallback = cb;
|
|
76
|
+
this.setDblTapCallback = (cb) => (this.dblTapCallback = cb);
|
|
77
|
+
this.setDblClickCallback = (cb) => (this.dblClickCallback = cb);
|
|
78
78
|
this.dblClickCallback = () => scale.autoScale(true);
|
|
79
79
|
this.dblTapCallback = () => scale.autoScale(true);
|
|
80
80
|
// drag to Y-scale and double click to auto scale
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import EventBus from '../events/event-bus';
|
|
7
7
|
import { ChartResizeHandler } from '../inputhandlers/chart-resize.handler';
|
|
8
8
|
export declare const HIT_TEST_PREFIX = "HIT_TEST_";
|
|
9
|
-
declare const drawerTypes: readonly ["MAIN_BACKGROUND", "MAIN_CLEAR", "HIT_TEST_CLEAR", "YAXIS_CLEAR", "SERIES_CLEAR", "OVER_SERIES_CLEAR", "HIT_TEST_DRAWINGS", "GRID", "
|
|
9
|
+
declare const drawerTypes: readonly ["MAIN_BACKGROUND", "MAIN_CLEAR", "HIT_TEST_CLEAR", "YAXIS_CLEAR", "SERIES_CLEAR", "OVER_SERIES_CLEAR", "HIT_TEST_DRAWINGS", "GRID", "X_AXIS", "Y_AXIS", "HIGH_LOW", "DYNAMIC_OBJECTS", "N_MAP_CHART", "PL_CHART", "WATERMARK", "EMPTY_CHART", "OFFLINE_CHART", "LABELS", "EVENTS", "HIT_TEST_EVENTS", "ZERO_LINE", "PL_ZERO_LINE_BACKGROUND", "CROSS_TOOL"];
|
|
10
10
|
export type DrawerType = typeof drawerTypes[number];
|
|
11
11
|
/**
|
|
12
12
|
* Manages the drawing process.
|
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -17,6 +17,7 @@ import { ScaleModel } from '../model/scale.model';
|
|
|
17
17
|
import VisualCandle from '../model/visual-candle';
|
|
18
18
|
import { CrossEvent, CrossEventProducerComponent } from './cross-event-producer.component';
|
|
19
19
|
import { TimeZoneModel } from '../model/time-zone.model';
|
|
20
|
+
import { MainCanvasTouchHandler } from './main-canvas-touch.handler';
|
|
20
21
|
export interface BaseHover {
|
|
21
22
|
readonly x: number;
|
|
22
23
|
readonly y: number;
|
|
@@ -52,13 +53,14 @@ export declare class HoverProducerComponent extends ChartBaseElement {
|
|
|
52
53
|
private canvasBoundsContainer;
|
|
53
54
|
private paneManager;
|
|
54
55
|
private timeZoneModel;
|
|
56
|
+
private mainCanvasTouchHandler;
|
|
55
57
|
private formatterFactory;
|
|
56
58
|
hoverSubject: BehaviorSubject<Hover | null>;
|
|
57
59
|
get hover(): Hover | null;
|
|
58
|
-
|
|
60
|
+
longTouchActivatedSubject: BehaviorSubject<boolean>;
|
|
59
61
|
private hoverProducerParts;
|
|
60
62
|
xFormatter: DateTimeFormatter;
|
|
61
|
-
constructor(crossEventProducer: CrossEventProducerComponent, scale: ScaleModel, config: FullChartConfig, chartModel: ChartModel, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, paneManager: PaneManager, timeZoneModel: TimeZoneModel, formatterFactory: (format: string) => (timestamp: number) => string);
|
|
63
|
+
constructor(crossEventProducer: CrossEventProducerComponent, scale: ScaleModel, config: FullChartConfig, chartModel: ChartModel, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, paneManager: PaneManager, timeZoneModel: TimeZoneModel, mainCanvasTouchHandler: MainCanvasTouchHandler, formatterFactory: (format: string) => (timestamp: number) => string);
|
|
62
64
|
/**
|
|
63
65
|
* This method is responsible for activating the chart hover functionality. It subscribes to several observables to
|
|
64
66
|
* update the hover when the chart is updated or when the user interacts with it. It also handles special behavior
|
|
@@ -89,7 +91,7 @@ export declare class HoverProducerComponent extends ChartBaseElement {
|
|
|
89
91
|
* @returns {Hover | undefined} - The hover object or undefined if there are no candles in the chart model.
|
|
90
92
|
* @todo Check if uuid is still useful here.
|
|
91
93
|
*/
|
|
92
|
-
|
|
94
|
+
createHover(x: number, y: number, uuid: string): Hover | undefined;
|
|
93
95
|
/**
|
|
94
96
|
* Creates a hover from a VisualCandle object and fires it.
|
|
95
97
|
* @param {VisualCandle} candle - The VisualCandle object to create the hover from.
|
|
@@ -4,12 +4,14 @@
|
|
|
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 { BehaviorSubject, merge } from 'rxjs';
|
|
7
|
+
import { filter, switchMap } from 'rxjs/operators';
|
|
7
8
|
import { CHART_UUID, CanvasElement } from '../canvas/canvas-bounds-container';
|
|
8
9
|
import { CandleHoverProducerPart } from '../model/candle-hover';
|
|
9
10
|
import { ChartBaseElement } from '../model/chart-base-element';
|
|
10
11
|
import { CompareSeriesHoverProducerPart } from '../model/compare-series-hover';
|
|
11
12
|
import { recalculateXFormatter } from '../model/date-time.formatter';
|
|
12
13
|
import { isMobile } from '../utils/device/browser.utils';
|
|
14
|
+
import { checkChartIsMoving } from './main-canvas-touch.handler';
|
|
13
15
|
/**
|
|
14
16
|
* Produces the Hover event.
|
|
15
17
|
* Hover is used for displaying values in legend and NOT related to displaying cross tool.
|
|
@@ -18,7 +20,7 @@ export class HoverProducerComponent extends ChartBaseElement {
|
|
|
18
20
|
get hover() {
|
|
19
21
|
return this.hoverSubject.getValue();
|
|
20
22
|
}
|
|
21
|
-
constructor(crossEventProducer, scale, config, chartModel, canvasInputListener, canvasBoundsContainer, paneManager, timeZoneModel, formatterFactory) {
|
|
23
|
+
constructor(crossEventProducer, scale, config, chartModel, canvasInputListener, canvasBoundsContainer, paneManager, timeZoneModel, mainCanvasTouchHandler, formatterFactory) {
|
|
22
24
|
super();
|
|
23
25
|
this.crossEventProducer = crossEventProducer;
|
|
24
26
|
this.scale = scale;
|
|
@@ -28,6 +30,7 @@ export class HoverProducerComponent extends ChartBaseElement {
|
|
|
28
30
|
this.canvasBoundsContainer = canvasBoundsContainer;
|
|
29
31
|
this.paneManager = paneManager;
|
|
30
32
|
this.timeZoneModel = timeZoneModel;
|
|
33
|
+
this.mainCanvasTouchHandler = mainCanvasTouchHandler;
|
|
31
34
|
this.formatterFactory = formatterFactory;
|
|
32
35
|
this.hoverSubject = new BehaviorSubject(null);
|
|
33
36
|
this.longTouchActivatedSubject = new BehaviorSubject(false);
|
|
@@ -50,8 +53,13 @@ export class HoverProducerComponent extends ChartBaseElement {
|
|
|
50
53
|
*/
|
|
51
54
|
doActivate() {
|
|
52
55
|
super.doActivate();
|
|
53
|
-
this.addRxSubscription(
|
|
54
|
-
|
|
56
|
+
this.addRxSubscription(
|
|
57
|
+
// required for initial legend initialization, do not show cross tool
|
|
58
|
+
this.chartModel.candlesSetSubject
|
|
59
|
+
.pipe(
|
|
60
|
+
// check the scale is valid before doing candle-based hover event
|
|
61
|
+
switchMap(() => this.scale.initialViewportValidSubject.pipe(filter(Boolean))))
|
|
62
|
+
.subscribe(() => {
|
|
55
63
|
const lastCandle = this.chartModel.getLastVisualCandle();
|
|
56
64
|
lastCandle && this.createAndFireHoverFromCandle(lastCandle);
|
|
57
65
|
}));
|
|
@@ -73,37 +81,86 @@ export class HoverProducerComponent extends ChartBaseElement {
|
|
|
73
81
|
}
|
|
74
82
|
}));
|
|
75
83
|
this.addRxSubscription(this.scale.xChanged.subscribe(() => this.fireLastCross()));
|
|
84
|
+
this.addRxSubscription(merge(this.chartModel.candlesSetSubject, this.timeZoneModel.observeTimeZoneChanged()).subscribe(() => this.recalculateCrossToolXFormatter()));
|
|
85
|
+
//#region crosstool touch events, special handling for mobile
|
|
76
86
|
this.addRxSubscription(this.canvasInputListener.observeTouchStart().subscribe(event => {
|
|
77
87
|
var _a;
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.createAndFireHover([
|
|
88
|
+
this.crossEventProducer.crossToolTouchInfo.isCommonTap = true;
|
|
89
|
+
const { clientX, clientY } = event.touches[0];
|
|
90
|
+
// if common tap - fire hover
|
|
91
|
+
if (!this.longTouchActivatedSubject.getValue()) {
|
|
92
|
+
const paneId = ((_a = this.paneManager.getPaneIfHit({ x: clientX, y: clientY })) === null || _a === void 0 ? void 0 : _a.uuid) || '';
|
|
93
|
+
this.createAndFireHover([clientX, clientY, paneId]);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// update crosstool placement coordinates
|
|
97
|
+
this.crossEventProducer.crossToolTouchInfo.temp = {
|
|
98
|
+
x: clientX - this.canvasBoundsContainer.canvasOnPageLocation.x,
|
|
99
|
+
y: clientY - this.canvasBoundsContainer.canvasOnPageLocation.y,
|
|
100
|
+
};
|
|
84
101
|
}
|
|
85
102
|
}));
|
|
86
|
-
// special handling for mobile
|
|
87
103
|
// on long touch - disable panning and show cross tool
|
|
88
104
|
const hitTest = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
|
|
89
105
|
this.addRxSubscription(this.canvasInputListener.observeLongTouchStart(hitTest).subscribe(event => {
|
|
90
106
|
var _a;
|
|
91
|
-
this.
|
|
107
|
+
this.crossEventProducer.crossToolHover = null;
|
|
108
|
+
this.crossEventProducer.crossToolTouchInfo.isCommonTap = false;
|
|
109
|
+
// don't lock chart and show crosshair if chart is being moved, crosstool is not enabled or we do pinch event
|
|
110
|
+
const longTouchCrosshairPredicate = this.mainCanvasTouchHandler.canvasTouchInfo.isMoving ||
|
|
111
|
+
this.chartModel.config.components.crossTool.type === 'none' ||
|
|
112
|
+
event.touches.length > 1;
|
|
113
|
+
if (longTouchCrosshairPredicate) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
92
116
|
this.longTouchActivatedSubject.next(true);
|
|
117
|
+
this.crossEventProducer.crossToolTouchInfo.isSet = false;
|
|
93
118
|
const x = event.touches[0].clientX - this.canvasBoundsContainer.canvasOnPageLocation.x;
|
|
94
119
|
const y = event.touches[0].clientY - this.canvasBoundsContainer.canvasOnPageLocation.y;
|
|
120
|
+
this.crossEventProducer.crossToolTouchInfo.fixed = {
|
|
121
|
+
x,
|
|
122
|
+
y,
|
|
123
|
+
};
|
|
95
124
|
const paneId = ((_a = this.paneManager.getPaneIfHit({ x, y })) === null || _a === void 0 ? void 0 : _a.uuid) || '';
|
|
96
125
|
this.createAndFireHover([x, y, paneId]);
|
|
97
126
|
this.crossEventProducer.crossSubject.next([x, y, paneId]);
|
|
127
|
+
this.paneManager.chartPanComponent.setChartPanningOptions(false, false);
|
|
98
128
|
}));
|
|
99
|
-
this.addRxSubscription(this.canvasInputListener.observeTouchEndDocument().subscribe(
|
|
100
|
-
|
|
101
|
-
|
|
129
|
+
this.addRxSubscription(this.canvasInputListener.observeTouchEndDocument().subscribe(event => {
|
|
130
|
+
var _a, _b;
|
|
131
|
+
const { clientX, clientY } = event.changedTouches[0];
|
|
132
|
+
const { fixed, temp } = this.crossEventProducer.crossToolTouchInfo;
|
|
133
|
+
const x = clientX - this.canvasBoundsContainer.canvasOnPageLocation.x;
|
|
134
|
+
const y = clientY - this.canvasBoundsContainer.canvasOnPageLocation.y;
|
|
135
|
+
// common tap without moving, hide crosstool
|
|
136
|
+
if (this.crossEventProducer.crossToolTouchInfo.isCommonTap &&
|
|
137
|
+
!checkChartIsMoving(x, temp.x, y, temp.y)) {
|
|
138
|
+
this.paneManager.chartPanComponent.setChartPanningOptions(true, true);
|
|
102
139
|
this.longTouchActivatedSubject.next(false);
|
|
103
140
|
this.crossEventProducer.fireCrossClose();
|
|
141
|
+
this.crossEventProducer.crossToolHover = null;
|
|
142
|
+
}
|
|
143
|
+
if (!this.crossEventProducer.crossToolTouchInfo.isSet) {
|
|
144
|
+
this.crossEventProducer.crossToolTouchInfo.isSet = true;
|
|
145
|
+
this.crossEventProducer.crossToolTouchInfo.fixed = {
|
|
146
|
+
x,
|
|
147
|
+
y,
|
|
148
|
+
};
|
|
149
|
+
this.crossEventProducer.crossToolTouchInfo.isSet = true;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const pane = (_b = (_a = this.crossEventProducer.crossToolHover) === null || _a === void 0 ? void 0 : _a.paneId) !== null && _b !== void 0 ? _b : 'CHART';
|
|
153
|
+
const paneBounds = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID(pane));
|
|
154
|
+
const paneYStart = paneBounds.y + 5;
|
|
155
|
+
const paneYEnd = paneBounds.y + paneBounds.height - 5;
|
|
156
|
+
const xDiff = x - temp.x;
|
|
157
|
+
const yDiff = y - temp.y;
|
|
158
|
+
const newX = fixed.x < 0 ? 0 : fixed.x > paneBounds.width ? paneBounds.width : (fixed.x += xDiff);
|
|
159
|
+
const newY = fixed.y < paneYStart ? paneYStart : fixed.y > paneYEnd ? paneYEnd : (fixed.y += yDiff);
|
|
160
|
+
this.crossEventProducer.crossToolTouchInfo.fixed = { x: newX, y: newY };
|
|
104
161
|
}
|
|
105
162
|
}));
|
|
106
|
-
|
|
163
|
+
//#endregion
|
|
107
164
|
}
|
|
108
165
|
/**
|
|
109
166
|
* Recalculates the cross tool X formatter.
|
|
@@ -192,12 +249,15 @@ export class HoverProducerComponent extends ChartBaseElement {
|
|
|
192
249
|
* @returns {void}
|
|
193
250
|
*/
|
|
194
251
|
fireHover(hover) {
|
|
195
|
-
var _a;
|
|
252
|
+
var _a, _b;
|
|
196
253
|
if (hover) {
|
|
197
254
|
// special handling for mobile
|
|
198
|
-
// set active candle + show cross tool only when
|
|
255
|
+
// set active candle + show cross tool only when crosstool is active
|
|
199
256
|
if (isMobile() && this.config.components.crossTool.type !== 'none') {
|
|
200
|
-
const
|
|
257
|
+
const crossToolHover = this.crossEventProducer.crossToolHover;
|
|
258
|
+
const candle = crossToolHover
|
|
259
|
+
? (_a = crossToolHover.candleHover) === null || _a === void 0 ? void 0 : _a.visualCandle.candle
|
|
260
|
+
: (_b = hover.candleHover) === null || _b === void 0 ? void 0 : _b.visualCandle.candle;
|
|
201
261
|
candle && this.chartModel.mainCandleSeries.setActiveCandle(candle);
|
|
202
262
|
}
|
|
203
263
|
this.hoverSubject.next(hover);
|
|
@@ -8,6 +8,8 @@ import { CanvasInputListenerComponent } from '../inputlisteners/canvas-input-lis
|
|
|
8
8
|
import { ScaleModel } from '../model/scale.model';
|
|
9
9
|
import { ChartAreaPanHandler } from '../components/chart/chart-area-pan.handler';
|
|
10
10
|
import { HitBoundsTest } from '../canvas/canvas-bounds-container';
|
|
11
|
+
import { Pixel } from '../model/scaling/viewport.model';
|
|
12
|
+
export declare const PIXELS_FOR_MOVE = 2;
|
|
11
13
|
/**
|
|
12
14
|
* Handles chart touch events.
|
|
13
15
|
*/
|
|
@@ -18,6 +20,13 @@ export declare class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
18
20
|
private mainCanvasParent;
|
|
19
21
|
private hitTest;
|
|
20
22
|
private touchedCandleIndexes;
|
|
23
|
+
canvasTouchInfo: {
|
|
24
|
+
touchStart: {
|
|
25
|
+
x: Pixel;
|
|
26
|
+
y: Pixel;
|
|
27
|
+
};
|
|
28
|
+
isMoving?: boolean;
|
|
29
|
+
};
|
|
21
30
|
constructor(chartAreaPanHandler: ChartAreaPanHandler, scale: ScaleModel, canvasInputListeners: CanvasInputListenerComponent, mainCanvasParent: Element, hitTest: HitBoundsTest);
|
|
22
31
|
/**
|
|
23
32
|
* Activates canvas input listeners for touch start and touch move events.
|
|
@@ -56,3 +65,4 @@ export declare class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
56
65
|
*/
|
|
57
66
|
pinchHandler(candleIndexes: Array<number>, touchPositions: number[]): void;
|
|
58
67
|
}
|
|
68
|
+
export declare const checkChartIsMoving: (x1: Pixel, x2: Pixel, y1: Pixel, y2: Pixel, pixelsToMove?: Pixel) => boolean;
|
|
@@ -4,6 +4,7 @@
|
|
|
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 { ChartBaseElement } from '../model/chart-base-element';
|
|
7
|
+
export const PIXELS_FOR_MOVE = 2;
|
|
7
8
|
/**
|
|
8
9
|
* Handles chart touch events.
|
|
9
10
|
*/
|
|
@@ -17,6 +18,12 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
17
18
|
this.hitTest = hitTest;
|
|
18
19
|
// 2 candles indexes touched by 2 fingers when pinching
|
|
19
20
|
this.touchedCandleIndexes = [0, 0];
|
|
21
|
+
// stores the information about touch events
|
|
22
|
+
this.canvasTouchInfo = {
|
|
23
|
+
touchStart: { x: 0, y: 0 },
|
|
24
|
+
// uses touch start to determine if chart is being moved
|
|
25
|
+
isMoving: false,
|
|
26
|
+
};
|
|
20
27
|
}
|
|
21
28
|
/**
|
|
22
29
|
* Activates canvas input listeners for touch start and touch move events.
|
|
@@ -34,6 +41,10 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
34
41
|
* @returns {void}
|
|
35
42
|
*/
|
|
36
43
|
handleTouchStartEvent(e) {
|
|
44
|
+
const { clientX, clientY } = e.touches[0];
|
|
45
|
+
if (e.touches.length === 1) {
|
|
46
|
+
this.canvasTouchInfo.touchStart = { x: clientX, y: clientY };
|
|
47
|
+
}
|
|
37
48
|
if (e.touches.length === 2) {
|
|
38
49
|
this.chartAreaPanHandler.deactivate();
|
|
39
50
|
// @ts-ignore
|
|
@@ -47,6 +58,11 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
47
58
|
* @returns {void}
|
|
48
59
|
*/
|
|
49
60
|
handleTouchMoveEvent(e) {
|
|
61
|
+
const { clientX, clientY } = e.touches[0];
|
|
62
|
+
const { touchStart } = this.canvasTouchInfo;
|
|
63
|
+
if (e.touches.length === 1) {
|
|
64
|
+
this.canvasTouchInfo.isMoving = checkChartIsMoving(clientX, touchStart.x, clientY, touchStart.y);
|
|
65
|
+
}
|
|
50
66
|
if (e.touches.length === 2) {
|
|
51
67
|
this.pinchHandler(this.touchedCandleIndexes, this.getXPositions(e));
|
|
52
68
|
}
|
|
@@ -56,6 +72,7 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
56
72
|
* @returns {void}
|
|
57
73
|
*/
|
|
58
74
|
handleTouchEndEvent(e) {
|
|
75
|
+
this.canvasTouchInfo.isMoving = false;
|
|
59
76
|
// zero touches means the user stopped resizing completely (both fingers are up)
|
|
60
77
|
if (e.touches.length === 0) {
|
|
61
78
|
this.chartAreaPanHandler.activate();
|
|
@@ -95,3 +112,4 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
95
112
|
this.scale.setXScale(first, last);
|
|
96
113
|
}
|
|
97
114
|
}
|
|
115
|
+
export const checkChartIsMoving = (x1, x2, y1, y2, pixelsToMove = PIXELS_FOR_MOVE) => Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) > pixelsToMove;
|
|
@@ -200,10 +200,8 @@ class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
200
200
|
};
|
|
201
201
|
this.addSubscription(subscribeListener(this.element, doubleTapListenerProducer, 'touchend'));
|
|
202
202
|
// workaround to handle long touch start/end for iOS
|
|
203
|
-
const longTouchListeners = (e, delay =
|
|
203
|
+
const longTouchListeners = (e, delay = 200) => {
|
|
204
204
|
e.preventDefault();
|
|
205
|
-
const initialCoords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
|
|
206
|
-
let coords = { x: 0, y: 0 };
|
|
207
205
|
let longTouchStart = false;
|
|
208
206
|
let timerLongTouchStart = null;
|
|
209
207
|
// start timeout for long touch
|
|
@@ -213,11 +211,8 @@ class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
213
211
|
}, delay);
|
|
214
212
|
const touchMoveHandler = (e) => {
|
|
215
213
|
e.preventDefault();
|
|
216
|
-
coords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
|
|
217
214
|
// clear long touch timeout if move area is bigger than pixelsForMove
|
|
218
|
-
if (
|
|
219
|
-
pixelsForMoveReset ||
|
|
220
|
-
e.touches.length > 1) {
|
|
215
|
+
if (e.touches.length > 1) {
|
|
221
216
|
timerLongTouchStart && clearTimeout(timerLongTouchStart);
|
|
222
217
|
}
|
|
223
218
|
};
|
|
@@ -123,7 +123,7 @@ export class CandleSeriesModel extends DataSeriesModel {
|
|
|
123
123
|
* @returns {HighLowWithIndex} - An object containing the high-low values along with their corresponding indexes.
|
|
124
124
|
*/
|
|
125
125
|
recalculateZippedHighLow() {
|
|
126
|
-
return (this.zippedHighLow = calculateCandlesHighLow(this.visualPoints.slice(this.dataIdxStart, this.dataIdxEnd)));
|
|
126
|
+
return (this.zippedHighLow = calculateCandlesHighLow(this.visualPoints.slice(this.dataIdxStart, this.dataIdxEnd + 1)));
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
129
|
* Updates the current price and the last price movement.
|
|
@@ -11,6 +11,7 @@ export declare const BASIC_CANDLE_WIDTH: Unit;
|
|
|
11
11
|
* @doc-tags-name Candle
|
|
12
12
|
*/
|
|
13
13
|
export interface Candle {
|
|
14
|
+
readonly id: string;
|
|
14
15
|
readonly hi: number;
|
|
15
16
|
readonly lo: number;
|
|
16
17
|
readonly open: number;
|
|
@@ -22,6 +23,8 @@ export interface Candle {
|
|
|
22
23
|
readonly impVolatility?: number;
|
|
23
24
|
readonly vwap?: number;
|
|
24
25
|
}
|
|
26
|
+
export declare const defaultSortCandles: (candles: Candle[]) => Candle[];
|
|
27
|
+
export declare const generateCandleId: (timestamp: number, hashValue: number | string) => string;
|
|
25
28
|
/**
|
|
26
29
|
* Provides the name of candle difference
|
|
27
30
|
* @param {Number} open
|
|
@@ -3,9 +3,14 @@
|
|
|
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 { hashCode } from '../utils/string.utils';
|
|
6
7
|
// Has no specific rule, just any number to use in units calculation.
|
|
7
8
|
// 1 - because why not? Easy to debug.
|
|
8
9
|
export const BASIC_CANDLE_WIDTH = 1;
|
|
10
|
+
export const defaultSortCandles = (candles) => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1));
|
|
11
|
+
export const generateCandleId = (timestamp, hashValue) => {
|
|
12
|
+
return `${timestamp}_${hashCode(hashValue.toString())}`;
|
|
13
|
+
};
|
|
9
14
|
/**
|
|
10
15
|
* Provides the name of candle difference
|
|
11
16
|
* @param {Number} open
|
|
@@ -45,7 +50,7 @@ export function hollowDirection(open, close) {
|
|
|
45
50
|
* @returns {Candle} A new Candle object with the same properties as the base object, with the option to modify the prices.
|
|
46
51
|
*/
|
|
47
52
|
export function copyCandle(base, idx, pricesAsClose = false) {
|
|
48
|
-
const { expansion, impVolatility, vwap, volume, timestamp } = base;
|
|
53
|
+
const { id, expansion, impVolatility, vwap, volume, timestamp } = base;
|
|
49
54
|
let hi = base.hi;
|
|
50
55
|
let lo = base.lo;
|
|
51
56
|
let open = base.open;
|
|
@@ -60,6 +65,7 @@ export function copyCandle(base, idx, pricesAsClose = false) {
|
|
|
60
65
|
_idx = idx;
|
|
61
66
|
}
|
|
62
67
|
return {
|
|
68
|
+
id,
|
|
63
69
|
hi,
|
|
64
70
|
lo,
|
|
65
71
|
open,
|
|
@@ -11,7 +11,7 @@ import { DataSeriesView } from './data-series-view';
|
|
|
11
11
|
import { DataSeriesConfig, DataSeriesPaintConfig, DataSeriesType } from './data-series.config';
|
|
12
12
|
import { HighLowWithIndex, ScaleModel } from './scale.model';
|
|
13
13
|
import { HighLowProvider } from './scaling/auto-scale.model';
|
|
14
|
-
import { Index, Unit, Viewable } from './scaling/viewport.model';
|
|
14
|
+
import { Index, Pixel, Unit, Viewable } from './scaling/viewport.model';
|
|
15
15
|
/**
|
|
16
16
|
* Properties are named in order to match VisualCandle interface
|
|
17
17
|
*/
|
|
@@ -22,11 +22,11 @@ export declare class VisualSeriesPoint {
|
|
|
22
22
|
/**
|
|
23
23
|
* returns y coordinate in pixels
|
|
24
24
|
*/
|
|
25
|
-
y(viewable: Viewable):
|
|
25
|
+
y(viewable: Viewable): Pixel;
|
|
26
26
|
/**
|
|
27
27
|
* returns x coordinate in pixels
|
|
28
28
|
*/
|
|
29
|
-
x(viewable: Viewable):
|
|
29
|
+
x(viewable: Viewable): Pixel;
|
|
30
30
|
clone(): VisualSeriesPoint;
|
|
31
31
|
}
|
|
32
32
|
export interface DataSeriesPoint {
|
|
@@ -30,7 +30,7 @@ export class VisualSeriesPoint {
|
|
|
30
30
|
* returns x coordinate in pixels
|
|
31
31
|
*/
|
|
32
32
|
x(viewable) {
|
|
33
|
-
return
|
|
33
|
+
return viewable.toX(this.centerUnit);
|
|
34
34
|
}
|
|
35
35
|
clone() {
|
|
36
36
|
return new VisualSeriesPoint(this.centerUnit, this.close);
|
|
@@ -125,7 +125,7 @@ export class ScaleModel extends ViewportModel {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
zoomXTo(state, zoomIn, forceNoAnimation) {
|
|
128
|
-
const initialStateCopy =
|
|
128
|
+
const initialStateCopy = this.export();
|
|
129
129
|
const constrainedState = this.scalePostProcessor(initialStateCopy, state);
|
|
130
130
|
this.zoomReached = this.calculateZoomReached(constrainedState.zoomX, zoomIn);
|
|
131
131
|
if (this.zoomReached.zoomIn || this.zoomReached.zoomOut) {
|
|
@@ -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 { Subject } from 'rxjs';
|
|
6
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
7
7
|
import { ChartBaseElement } from '../chart-base-element';
|
|
8
8
|
import { ViewportMovementAnimation } from '../../animation/types/viewport-movement-animation';
|
|
9
9
|
import { Bounds } from '../bounds.model';
|
|
@@ -92,6 +92,7 @@ export declare abstract class ViewportModel extends ChartBaseElement implements
|
|
|
92
92
|
start: number;
|
|
93
93
|
end: number;
|
|
94
94
|
}>;
|
|
95
|
+
initialViewportValidSubject: BehaviorSubject<boolean>;
|
|
95
96
|
protected doActivate(): void;
|
|
96
97
|
protected doDeactivate(): void;
|
|
97
98
|
/**
|
|
@@ -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 { Subject } from 'rxjs';
|
|
6
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
7
7
|
import { distinctUntilChanged, map, share } from 'rxjs/operators';
|
|
8
8
|
import { ChartBaseElement } from '../chart-base-element';
|
|
9
9
|
import { keys } from '../../utils/object.utils';
|
|
@@ -50,10 +50,15 @@ export class ViewportModel extends ChartBaseElement {
|
|
|
50
50
|
start: this.yStart,
|
|
51
51
|
end: this.yEnd,
|
|
52
52
|
})), distinctUntilChanged((p, c) => p.start === c.start && p.end === c.end), share());
|
|
53
|
+
this.initialViewportValidSubject = new BehaviorSubject(false);
|
|
53
54
|
}
|
|
54
55
|
//endregion
|
|
55
56
|
doActivate() {
|
|
56
57
|
super.doActivate();
|
|
58
|
+
this.addRxSubscription(this.changed.subscribe(() => {
|
|
59
|
+
!this.initialViewportValidSubject.getValue() &&
|
|
60
|
+
this.initialViewportValidSubject.next(this.isViewportValid());
|
|
61
|
+
}));
|
|
57
62
|
}
|
|
58
63
|
doDeactivate() {
|
|
59
64
|
super.doDeactivate();
|
|
@@ -87,9 +87,7 @@ export class TimeZoneModel {
|
|
|
87
87
|
// In JS Date object is created with local tz offset,
|
|
88
88
|
// so we have to subtract localOffset from current time
|
|
89
89
|
return time => {
|
|
90
|
-
return new Date(time +
|
|
91
|
-
getTimezoneOffset(timezone, time) +
|
|
92
|
-
new Date(time).getTimezoneOffset() * timeMultiplier);
|
|
90
|
+
return new Date(time + getTimezoneOffset(timezone, time) + new Date(time).getTimezoneOffset() * timeMultiplier);
|
|
93
91
|
};
|
|
94
92
|
}
|
|
95
93
|
}
|