@devexperts/dxcharts-lite 2.2.0 → 2.3.0
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/canvas/canvas-bounds-container.d.ts +2 -2
- package/dist/chart/canvas/canvas-bounds-container.js +2 -2
- package/dist/chart/chart.config.d.ts +17 -4
- package/dist/chart/chart.config.js +6 -2
- package/dist/chart/components/chart/chart-area-pan.handler.js +10 -5
- package/dist/chart/components/cross_tool/cross-tool.model.js +1 -1
- package/dist/chart/components/snapshot/snapshot.component.js +1 -0
- package/dist/chart/components/volumes/separate-volumes.component.js +2 -1
- package/dist/chart/components/volumes/volumes.formatter.d.ts +1 -1
- package/dist/chart/components/volumes/volumes.formatter.js +28 -25
- package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +5 -4
- package/dist/chart/components/y_axis/y-axis-scale.handler.js +9 -9
- package/dist/chart/components/y_axis/y-axis.component.js +1 -0
- package/dist/chart/drawers/data-series.drawer.js +1 -1
- package/dist/chart/inputlisteners/canvas-input-listener.component.d.ts +9 -0
- package/dist/chart/inputlisteners/canvas-input-listener.component.js +38 -1
- package/dist/chart/model/scale.model.d.ts +3 -2
- package/dist/chart/model/scale.model.js +23 -5
- package/dist/chart/model/scaling/constrait.functions.d.ts +1 -1
- package/dist/chart/model/scaling/constrait.functions.js +1 -2
- package/dist/chart/model/scaling/lock-ratio.model.d.ts +8 -2
- package/dist/chart/model/scaling/lock-ratio.model.js +18 -3
- package/dist/chart/utils/device/touchpad.utils.d.ts +3 -3
- package/dist/chart/utils/device/touchpad.utils.js +3 -5
- package/dist/chart/utils/math.utils.d.ts +0 -1
- package/dist/chart/utils/math.utils.js +1 -1
- package/dist/dxchart.min.js +4 -4
- package/package.json +1 -1
|
@@ -35,11 +35,11 @@ export declare class CanvasElement {
|
|
|
35
35
|
static CHART_WITH_Y_AXIS: string;
|
|
36
36
|
static EVENTS: string;
|
|
37
37
|
/**
|
|
38
|
-
* @
|
|
38
|
+
* @returns pane bounds for the main chart
|
|
39
39
|
*/
|
|
40
40
|
static CHART: string;
|
|
41
41
|
/**
|
|
42
|
-
* @
|
|
42
|
+
* @returns y-axis bounds for the main chart
|
|
43
43
|
*/
|
|
44
44
|
static Y_AXIS: string;
|
|
45
45
|
}
|
|
@@ -31,11 +31,11 @@ CanvasElement.ALL_PANES = 'ALL_PANES';
|
|
|
31
31
|
CanvasElement.CHART_WITH_Y_AXIS = 'CHART_WITH_Y_AXIS';
|
|
32
32
|
CanvasElement.EVENTS = 'EVENTS';
|
|
33
33
|
/**
|
|
34
|
-
* @
|
|
34
|
+
* @returns pane bounds for the main chart
|
|
35
35
|
*/
|
|
36
36
|
CanvasElement.CHART = CanvasElement.PANE_UUID(CHART_UUID);
|
|
37
37
|
/**
|
|
38
|
-
* @
|
|
38
|
+
* @returns y-axis bounds for the main chart
|
|
39
39
|
*/
|
|
40
40
|
CanvasElement.Y_AXIS = CanvasElement.PANE_UUID_Y_AXIS(CHART_UUID);
|
|
41
41
|
export { CanvasElement };
|
|
@@ -233,10 +233,23 @@ export interface ChartScale {
|
|
|
233
233
|
* When dragging chart under specific angle - will automatically disable auto-scale.
|
|
234
234
|
*/
|
|
235
235
|
autoScaleDisableOnDrag: AutoScaleDisableOnDrag;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
236
|
+
zoomSensitivity: {
|
|
237
|
+
/**
|
|
238
|
+
* Value is related to zoom event (zooming chart via mouse wheel)
|
|
239
|
+
* 0..1 ratio of full viewport; 0.5 = middle, 0.75 = 3/4 of viewport
|
|
240
|
+
*/
|
|
241
|
+
wheel: number;
|
|
242
|
+
/**
|
|
243
|
+
* Value is related to pinch touchpad event (zooming chart via touchpad)
|
|
244
|
+
* 0..1 ratio of full viewport; 0.5 = middle, 0.75 = 3/4 of viewport
|
|
245
|
+
*/
|
|
246
|
+
pinch: number;
|
|
247
|
+
/**
|
|
248
|
+
* Value is related to glide touchpad event (scrolling chart via touchpad)
|
|
249
|
+
* 0..1 ratio of full viewport; 0.5 = middle, 0.75 = 3/4 of viewport
|
|
250
|
+
*/
|
|
251
|
+
glide: number;
|
|
252
|
+
};
|
|
240
253
|
/**
|
|
241
254
|
* Defines how much items (candles) will be in viewport when chart applies basic scale
|
|
242
255
|
*/
|
|
@@ -41,9 +41,13 @@ export const getDefaultConfig = () => ({
|
|
|
41
41
|
yDiff: 80,
|
|
42
42
|
},
|
|
43
43
|
inverse: false,
|
|
44
|
-
zoomSensitivity:
|
|
44
|
+
zoomSensitivity: {
|
|
45
|
+
wheel: 0.25,
|
|
46
|
+
pinch: 0.05,
|
|
47
|
+
glide: 0.05,
|
|
48
|
+
},
|
|
45
49
|
defaultViewportItems: 100,
|
|
46
|
-
disableAnimations: false
|
|
50
|
+
disableAnimations: false,
|
|
47
51
|
},
|
|
48
52
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
49
53
|
components: {
|
|
@@ -60,10 +60,8 @@ export class ChartAreaPanHandler extends ChartBaseElement {
|
|
|
60
60
|
* @param {WheelEvent} e - Wheel event
|
|
61
61
|
* @returns {void}
|
|
62
62
|
*/
|
|
63
|
-
this.zoomXHandler = (e) => {
|
|
64
|
-
const isTouchpad = touchpadDetector(e);
|
|
63
|
+
this.zoomXHandler = (e, zoomSensitivity) => {
|
|
65
64
|
const zoomIn = e.deltaY < 0;
|
|
66
|
-
const zoomSensitivity = isTouchpad ? getTouchpadSensitivity(this.config) : this.config.scale.zoomSensitivity;
|
|
67
65
|
if (this.config.scale.zoomToCursor) {
|
|
68
66
|
const b = this.canvasBoundsContainer.getBounds(CanvasElement.CANVAS);
|
|
69
67
|
const canvasW = b.width;
|
|
@@ -115,7 +113,13 @@ export class ChartAreaPanHandler extends ChartBaseElement {
|
|
|
115
113
|
//#endregion
|
|
116
114
|
this.addRxSubscription(merge(this.canvasInputListener.observeWheel(allPanesHitTest), this.canvasInputListener.observePinch(allPanesHitTest))
|
|
117
115
|
.pipe(throttleTime(this.wheelTrottleTime, undefined, { trailing: true, leading: true }))
|
|
118
|
-
.subscribe(
|
|
116
|
+
.subscribe(e => {
|
|
117
|
+
const isTouchpad = touchpadDetector(e);
|
|
118
|
+
const zoomSensitivity = isTouchpad
|
|
119
|
+
? getTouchpadSensitivity(this.config.components.yAxis.type, this.config.scale.zoomSensitivity.pinch)
|
|
120
|
+
: this.config.scale.zoomSensitivity.wheel;
|
|
121
|
+
this.zoomXHandler(e, zoomSensitivity);
|
|
122
|
+
}));
|
|
119
123
|
this.addRxSubscription(this.canvasInputListener
|
|
120
124
|
.observeScrollGesture()
|
|
121
125
|
.pipe(throttleTime(this.wheelTrottleTime, undefined, { trailing: true, leading: true }))
|
|
@@ -134,7 +138,8 @@ export class ChartAreaPanHandler extends ChartBaseElement {
|
|
|
134
138
|
this.scale.moveXStart(this.scale.xStart - unitsDelta);
|
|
135
139
|
}
|
|
136
140
|
else if (deltaY !== 0 && Math.abs(deltaY) > Math.abs(deltaX)) {
|
|
137
|
-
this.
|
|
141
|
+
const zoomSensitivity = getTouchpadSensitivity(this.config.components.yAxis.type, this.config.scale.zoomSensitivity.glide);
|
|
142
|
+
this.zoomXHandler(e, zoomSensitivity);
|
|
138
143
|
}
|
|
139
144
|
this.bus.fireDraw();
|
|
140
145
|
}));
|
|
@@ -107,7 +107,7 @@ export class CrossToolModel extends ChartBaseElement {
|
|
|
107
107
|
else {
|
|
108
108
|
this.currentHover.y = hover.y;
|
|
109
109
|
}
|
|
110
|
-
this.currentHover.paneId =
|
|
110
|
+
this.currentHover.paneId = hover.paneId;
|
|
111
111
|
this.currentHoverSubject.next(this.currentHover);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -40,6 +40,7 @@ export class SnapshotComponent extends ChartBaseElement {
|
|
|
40
40
|
ctx.drawImage(this.elements.mainCanvas, 0, 0, width, height);
|
|
41
41
|
ctx.drawImage(this.elements.dynamicObjectsCanvas, 0, 0, width, height);
|
|
42
42
|
ctx.drawImage(this.elements.crossToolCanvas, 0, 0, width, height);
|
|
43
|
+
ctx.drawImage(this.elements.yAxisLabelsCanvas, 0, 0, width, height);
|
|
43
44
|
userDrawCallback && userDrawCallback(ctx);
|
|
44
45
|
return new Promise((resolve, fail) => this.elements.snapshotCanvas.toBlob(blob => {
|
|
45
46
|
return blob ? resolve(blob) : fail('Blob is null');
|
|
@@ -31,9 +31,10 @@ class SeparateVolumesComponent extends ChartBaseElement {
|
|
|
31
31
|
*/
|
|
32
32
|
activateSeparateVolumes() {
|
|
33
33
|
if (this.paneManager.panes[SeparateVolumesComponent.UUID] === undefined) {
|
|
34
|
+
const precision = 1;
|
|
34
35
|
const volumePane = this.paneManager.createPane(SeparateVolumesComponent.UUID, {
|
|
35
36
|
paneFormatters: {
|
|
36
|
-
regular: volumeFormatter,
|
|
37
|
+
regular: (value) => volumeFormatter(value, precision),
|
|
37
38
|
},
|
|
38
39
|
useDefaultHighLow: false,
|
|
39
40
|
increment: 1,
|
|
@@ -3,4 +3,4 @@
|
|
|
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
|
-
export declare const volumeFormatter: (value: number) => string;
|
|
6
|
+
export declare const volumeFormatter: (value: number, precision?: number) => string;
|
|
@@ -3,34 +3,37 @@
|
|
|
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
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const roundedValue = Math.round(value * rounder) / rounder;
|
|
14
|
-
if (roundedValue < 1 && roundedValue >= MIN_VALUE) {
|
|
15
|
-
return roundedValue
|
|
16
|
-
.toFixed(DEFAULT_PRECISION)
|
|
17
|
-
.replace(TRAILLING_ZEROES_REGEXP, '')
|
|
18
|
-
.replace(TRAILLING_FRACTION_WITH_ZEROES_REGEXP, '');
|
|
6
|
+
export const volumeFormatter = (value, precision = 1) => {
|
|
7
|
+
function formatNumber(value) {
|
|
8
|
+
let formattedResult;
|
|
9
|
+
const priceScale = Math.pow(10, precision);
|
|
10
|
+
value = Math.round(value * priceScale) / priceScale;
|
|
11
|
+
if (value >= 1e-15 && value < 1) {
|
|
12
|
+
formattedResult = value.toFixed(precision).replace(/\.?0+$/, ''); // regex removes trailing zeroes
|
|
19
13
|
}
|
|
20
14
|
else {
|
|
21
|
-
|
|
15
|
+
formattedResult = String(value);
|
|
22
16
|
}
|
|
23
|
-
|
|
24
|
-
if (Math.abs(value) > 999999999) {
|
|
25
|
-
value = Math.round(value / 1000000) * 1000000;
|
|
26
|
-
return formatValue(value / 1000000000, 'B');
|
|
17
|
+
return formattedResult.replace(/(\.[1-9]*)0+$/, (e, p1) => p1);
|
|
27
18
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
function format(value) {
|
|
20
|
+
let sign = '';
|
|
21
|
+
if (value < 0) {
|
|
22
|
+
sign = '-';
|
|
23
|
+
value = -value;
|
|
24
|
+
}
|
|
25
|
+
if (value < 995) {
|
|
26
|
+
return sign + formatNumber(value);
|
|
27
|
+
}
|
|
28
|
+
if (value < 999995) {
|
|
29
|
+
return sign + formatNumber(value / 1000) + 'K';
|
|
30
|
+
}
|
|
31
|
+
if (value < 999999995) {
|
|
32
|
+
value = 1000 * Math.round(value / 1000);
|
|
33
|
+
return sign + formatNumber(value / 1000000) + 'M';
|
|
34
|
+
}
|
|
35
|
+
value = 1000000 * Math.round(value / 1000000);
|
|
36
|
+
return sign + formatNumber(value / 1000000000) + 'B';
|
|
34
37
|
}
|
|
35
|
-
return
|
|
38
|
+
return format(value);
|
|
36
39
|
};
|
|
@@ -9,23 +9,24 @@ import { YAxisConfig } from '../../chart.config';
|
|
|
9
9
|
import EventBus from '../../events/event-bus';
|
|
10
10
|
import { ChartBaseElement } from '../../model/chart-base-element';
|
|
11
11
|
import { CanvasInputListenerComponent } from '../../inputlisteners/canvas-input-listener.component';
|
|
12
|
-
import { Pixel, Unit
|
|
12
|
+
import { Pixel, Unit } from '../../model/scaling/viewport.model';
|
|
13
13
|
import { ChartPanComponent } from '../pan/chart-pan.component';
|
|
14
|
+
import { ScaleModel } from '../../model/scale.model';
|
|
14
15
|
/**
|
|
15
16
|
* Handles the mouse drag on Y axis - to zoom the viewport vertically.
|
|
16
17
|
* @doc-tags scaling,zoom,viewport
|
|
17
18
|
*/
|
|
18
19
|
export declare class YAxisScaleHandler extends ChartBaseElement {
|
|
19
20
|
private bus;
|
|
20
|
-
private
|
|
21
|
-
private
|
|
21
|
+
private scale;
|
|
22
|
+
private bounds;
|
|
22
23
|
private autoScaleCallback;
|
|
23
24
|
yAxisDragEndSubject: Subject<void>;
|
|
24
25
|
lastYStart: Unit;
|
|
25
26
|
lastYEnd: Unit;
|
|
26
27
|
lastYHeight: Unit;
|
|
27
28
|
lastYPxHeight: Pixel;
|
|
28
|
-
constructor(bus: EventBus, config: YAxisConfig,
|
|
29
|
+
constructor(bus: EventBus, config: YAxisConfig, panning: ChartPanComponent, scale: ScaleModel, canvasInputListener: CanvasInputListenerComponent, bounds: CanvasBoundsContainer, hitTest: HitBoundsTest, autoScaleCallback: (auto: boolean) => void);
|
|
29
30
|
private onYDragStart;
|
|
30
31
|
private onYDragTick;
|
|
31
32
|
private onYDragEnd;
|
|
@@ -14,11 +14,11 @@ const FULL_Y_HEIGHT_ZOOM_FACTOR = 10;
|
|
|
14
14
|
* @doc-tags scaling,zoom,viewport
|
|
15
15
|
*/
|
|
16
16
|
export class YAxisScaleHandler extends ChartBaseElement {
|
|
17
|
-
constructor(bus, config,
|
|
17
|
+
constructor(bus, config, panning, scale, canvasInputListener, bounds, hitTest, autoScaleCallback) {
|
|
18
18
|
super();
|
|
19
19
|
this.bus = bus;
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
20
|
+
this.scale = scale;
|
|
21
|
+
this.bounds = bounds;
|
|
22
22
|
this.autoScaleCallback = autoScaleCallback;
|
|
23
23
|
this.yAxisDragEndSubject = new Subject();
|
|
24
24
|
this.lastYStart = 0;
|
|
@@ -26,10 +26,10 @@ export class YAxisScaleHandler extends ChartBaseElement {
|
|
|
26
26
|
this.lastYHeight = 0;
|
|
27
27
|
this.lastYPxHeight = 0;
|
|
28
28
|
this.onYDragStart = () => {
|
|
29
|
-
this.lastYStart = this.
|
|
30
|
-
this.lastYEnd = this.
|
|
31
|
-
this.lastYHeight = this.
|
|
32
|
-
this.lastYPxHeight = this.
|
|
29
|
+
this.lastYStart = this.scale.yStart;
|
|
30
|
+
this.lastYEnd = this.scale.yEnd;
|
|
31
|
+
this.lastYHeight = this.scale.yEnd - this.scale.yStart;
|
|
32
|
+
this.lastYPxHeight = this.bounds.getBounds(CanvasElement.Y_AXIS).height;
|
|
33
33
|
};
|
|
34
34
|
this.onYDragTick = (dragInfo) => {
|
|
35
35
|
const { delta: absoluteYDelta } = dragInfo;
|
|
@@ -48,7 +48,7 @@ export class YAxisScaleHandler extends ChartBaseElement {
|
|
|
48
48
|
const newYStart = this.lastYStart - delta;
|
|
49
49
|
const newYEnd = this.lastYEnd + delta;
|
|
50
50
|
this.autoScaleCallback(false);
|
|
51
|
-
this.
|
|
51
|
+
this.scale.setYScale(newYStart, newYEnd);
|
|
52
52
|
this.bus.fireDraw();
|
|
53
53
|
};
|
|
54
54
|
this.onYDragEnd = () => {
|
|
@@ -61,7 +61,7 @@ export class YAxisScaleHandler extends ChartBaseElement {
|
|
|
61
61
|
onDragTick: callIfPredicateTrue(this.onYDragTick, dragPredicate),
|
|
62
62
|
onDragStart: callIfPredicateTrue(this.onYDragStart, dragPredicate),
|
|
63
63
|
onDragEnd: callIfPredicateTrue(this.onYDragEnd, dragPredicate),
|
|
64
|
-
}, canvasInputListener,
|
|
64
|
+
}, canvasInputListener, panning, {
|
|
65
65
|
disableChartPanning: false,
|
|
66
66
|
});
|
|
67
67
|
this.addChildEntity(dragNDropYComponent);
|
|
@@ -151,6 +151,7 @@ export class YAxisComponent extends ChartBaseElement {
|
|
|
151
151
|
setAxisType(type) {
|
|
152
152
|
if (type !== this.state.type) {
|
|
153
153
|
this.state.type = type;
|
|
154
|
+
this.config.components.yAxis.type = type;
|
|
154
155
|
this.axisTypeSetSubject.next(type);
|
|
155
156
|
this.scale.autoScale(true);
|
|
156
157
|
this.model.fancyLabelsModel.updateLabels(true);
|
|
@@ -53,7 +53,7 @@ export const setLineWidth = (ctx, lineWidth, dataSeries, drawerConfig, seriesSel
|
|
|
53
53
|
ctx.lineWidth = drawerConfig.forceBold;
|
|
54
54
|
}
|
|
55
55
|
else if (dataSeries.hovered) {
|
|
56
|
-
ctx.lineWidth = seriesSelectedWidth;
|
|
56
|
+
ctx.lineWidth = lineWidth !== seriesSelectedWidth ? lineWidth + 1 : seriesSelectedWidth;
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
59
|
ctx.lineWidth = lineWidth;
|
|
@@ -44,6 +44,7 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
44
44
|
private mouseUpDocumentSubject;
|
|
45
45
|
private wheelSubject;
|
|
46
46
|
private touchStartSubject;
|
|
47
|
+
private touchStartTimestamp;
|
|
47
48
|
private touchMoveSubject;
|
|
48
49
|
private touchEndSubject;
|
|
49
50
|
private touchCancelSubject;
|
|
@@ -52,6 +53,7 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
52
53
|
private contextMenuSubject;
|
|
53
54
|
private pinchSubject;
|
|
54
55
|
private scrollGestureSubject;
|
|
56
|
+
private fastTouchScroll;
|
|
55
57
|
mouseLeavesCanvasSubject: Subject<boolean>;
|
|
56
58
|
dragStartPoint: Point;
|
|
57
59
|
prevDragPoint: Point;
|
|
@@ -312,6 +314,13 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
312
314
|
* @returns {Observable<TouchEvent>} - An Observable that emits a TouchEvent when a long touch is detected on the current element.
|
|
313
315
|
*/
|
|
314
316
|
observeLongTouchEnd(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
|
|
317
|
+
/**
|
|
318
|
+
* Returns an Observable that emits a Touch whenever a fast scroll is detected.
|
|
319
|
+
* Fast scroll happens whenever chart or any other pane were moved faster than usual
|
|
320
|
+
* The Observable is created from a Subject that is subscribed to by the component's template.
|
|
321
|
+
* @returns {Observable<TouchEvent>} An Observable that emits a TouchEvent whenever a fast scroll is detected.
|
|
322
|
+
*/
|
|
323
|
+
observeFastTouchScroll(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
|
|
315
324
|
/**
|
|
316
325
|
* Returns the current point of the object.
|
|
317
326
|
* @returns {Point} The current point of the object.
|
|
@@ -46,6 +46,7 @@ class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
46
46
|
this.mouseUpDocumentSubject = new Subject();
|
|
47
47
|
this.wheelSubject = new Subject();
|
|
48
48
|
this.touchStartSubject = new Subject();
|
|
49
|
+
this.touchStartTimestamp = 0;
|
|
49
50
|
this.touchMoveSubject = new Subject();
|
|
50
51
|
this.touchEndSubject = new Subject();
|
|
51
52
|
this.touchCancelSubject = new Subject();
|
|
@@ -54,6 +55,7 @@ class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
54
55
|
this.contextMenuSubject = new Subject();
|
|
55
56
|
this.pinchSubject = new Subject();
|
|
56
57
|
this.scrollGestureSubject = new Subject();
|
|
58
|
+
this.fastTouchScroll = new Subject();
|
|
57
59
|
this.mouseLeavesCanvasSubject = new Subject();
|
|
58
60
|
// point at which start dragging
|
|
59
61
|
this.dragStartPoint = { x: 0, y: 0 };
|
|
@@ -236,9 +238,33 @@ class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
236
238
|
this.element.addEventListener('touchend', touchEndHandler);
|
|
237
239
|
};
|
|
238
240
|
this.addSubscription(subscribeListener(this.element, (e) => longTouchListeners(e), 'touchstart'));
|
|
241
|
+
const fastScrollListenerProducer = (e) => {
|
|
242
|
+
e.preventDefault();
|
|
243
|
+
// should work only if dragged to the left
|
|
244
|
+
if (this.prevDragPoint.x > this.dragStartPoint.x) {
|
|
245
|
+
// in percent, perhaps should be changed to just pixels,
|
|
246
|
+
// because landscape and portait orientations would give different % results
|
|
247
|
+
const minDistance = 35;
|
|
248
|
+
// in ms, should be lower to detect as "fast"
|
|
249
|
+
const maxTime = 250;
|
|
250
|
+
const touchStartTs = this.touchStartTimestamp;
|
|
251
|
+
const touchEndTs = Date.now();
|
|
252
|
+
const time = touchEndTs - touchStartTs;
|
|
253
|
+
const distance = ((this.prevDragPoint.x - this.dragStartPoint.x) / this.canvasBounds.width) * 100;
|
|
254
|
+
const isRightDistance = distance > minDistance;
|
|
255
|
+
const isRightTime = time <= maxTime;
|
|
256
|
+
if (isRightDistance && isRightTime) {
|
|
257
|
+
this.fastTouchScroll.next(e);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
this.addSubscription(subscribeListener(this.element, fastScrollListenerProducer, 'touchend'));
|
|
239
262
|
}
|
|
240
263
|
this.addSubscription(subscribeListener(this.element, leftMouseButtonListener(() => this.dbClickSubject.next(this.currentPoint)), 'dblclick'));
|
|
241
|
-
this.addSubscription(subscribeListener(this.element, (e) =>
|
|
264
|
+
this.addSubscription(subscribeListener(this.element, (e) => {
|
|
265
|
+
this.touchStartSubject.next(e);
|
|
266
|
+
this.touchStartTimestamp = Date.now();
|
|
267
|
+
}, 'touchstart'));
|
|
242
268
|
this.addSubscription(subscribeListener(this.element, (e) => this.touchMoveSubject.next(e), 'touchmove', true));
|
|
243
269
|
this.addSubscription(subscribeListener(this.element, (e) => this.touchEndSubject.next(e), 'touchend'));
|
|
244
270
|
this.addSubscription(subscribeListener(this.element, (e) => this.touchCancelSubject.next(e), 'touchcancel'));
|
|
@@ -643,6 +669,17 @@ class CanvasInputListenerComponent extends ChartBaseElement {
|
|
|
643
669
|
.asObservable()
|
|
644
670
|
.pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)));
|
|
645
671
|
}
|
|
672
|
+
/**
|
|
673
|
+
* Returns an Observable that emits a Touch whenever a fast scroll is detected.
|
|
674
|
+
* Fast scroll happens whenever chart or any other pane were moved faster than usual
|
|
675
|
+
* The Observable is created from a Subject that is subscribed to by the component's template.
|
|
676
|
+
* @returns {Observable<TouchEvent>} An Observable that emits a TouchEvent whenever a fast scroll is detected.
|
|
677
|
+
*/
|
|
678
|
+
observeFastTouchScroll(hitBoundsTest = () => true) {
|
|
679
|
+
return this.fastTouchScroll
|
|
680
|
+
.asObservable()
|
|
681
|
+
.pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)));
|
|
682
|
+
}
|
|
646
683
|
/**
|
|
647
684
|
* Returns the current point of the object.
|
|
648
685
|
* @returns {Point} The current point of the object.
|
|
@@ -71,13 +71,13 @@ export declare class ScaleModel extends ViewportModel {
|
|
|
71
71
|
* @param forceNoAnimation Whether to skip animation.
|
|
72
72
|
* @param zoomSensitivity The sensitivity of the zoom.
|
|
73
73
|
*/
|
|
74
|
-
zoomXToPercent(viewportPercent: ViewportPercent, zoomIn: boolean, forceNoAnimation
|
|
74
|
+
zoomXToPercent(viewportPercent: ViewportPercent, zoomIn: boolean, forceNoAnimation: boolean | undefined, zoomSensitivity: number): void;
|
|
75
75
|
/**
|
|
76
76
|
* Zooms the X axis of the chart relativly to the end of the data range.
|
|
77
77
|
* @param zoomIn - If true, the chart will be zoomed in. If false, the chart will be zoomed out.
|
|
78
78
|
* @param zoomSensitivity - The sensitivity of the zoom. Default value is taken from the configuration object.
|
|
79
79
|
*/
|
|
80
|
-
zoomXToEnd(zoomIn: boolean, zoomSensitivity
|
|
80
|
+
zoomXToEnd(zoomIn: boolean, zoomSensitivity: number): void;
|
|
81
81
|
haltAnimation(): void;
|
|
82
82
|
private zoomXTo;
|
|
83
83
|
/**
|
|
@@ -89,6 +89,7 @@ export declare class ScaleModel extends ViewportModel {
|
|
|
89
89
|
* @param forceNoAutoScale - force NOT apply auto-scaling (for lazy loading)
|
|
90
90
|
*/
|
|
91
91
|
setXScale(xStart: Unit, xEnd: Unit): void;
|
|
92
|
+
setYScale(yStart: Unit, yEnd: Unit, fire?: boolean): void;
|
|
92
93
|
/**
|
|
93
94
|
* Moves both xStart and xEnd without changing the viewport width (zoom).
|
|
94
95
|
* Works without animation.
|
|
@@ -8,7 +8,7 @@ import { startViewportModelAnimation } from '../animation/viewport-model-animati
|
|
|
8
8
|
import { cloneUnsafe } from '../utils/object.utils';
|
|
9
9
|
import { AutoScaleViewportSubModel } from './scaling/auto-scale.model';
|
|
10
10
|
import { zoomConstraint } from './scaling/constrait.functions';
|
|
11
|
-
import {
|
|
11
|
+
import { changeXToKeepRatio, changeYToKeepRatio, ratioFromZoomXY } from './scaling/lock-ratio.model';
|
|
12
12
|
import { moveXStart, moveYStart } from './scaling/move-chart.functions';
|
|
13
13
|
import { ViewportModel, compareStates } from './scaling/viewport.model';
|
|
14
14
|
import { zoomXToEndViewportCalculator, zoomXToPercentViewportCalculator } from './scaling/x-zooming.functions';
|
|
@@ -81,7 +81,7 @@ export class ScaleModel extends ViewportModel {
|
|
|
81
81
|
* @param forceNoAnimation Whether to skip animation.
|
|
82
82
|
* @param zoomSensitivity The sensitivity of the zoom.
|
|
83
83
|
*/
|
|
84
|
-
zoomXToPercent(viewportPercent, zoomIn, forceNoAnimation = false, zoomSensitivity
|
|
84
|
+
zoomXToPercent(viewportPercent, zoomIn, forceNoAnimation = false, zoomSensitivity) {
|
|
85
85
|
const disabledAnimations = this.config.scale.disableAnimations || forceNoAnimation;
|
|
86
86
|
if (disabledAnimations) {
|
|
87
87
|
this.haltAnimation();
|
|
@@ -96,7 +96,7 @@ export class ScaleModel extends ViewportModel {
|
|
|
96
96
|
* @param zoomIn - If true, the chart will be zoomed in. If false, the chart will be zoomed out.
|
|
97
97
|
* @param zoomSensitivity - The sensitivity of the zoom. Default value is taken from the configuration object.
|
|
98
98
|
*/
|
|
99
|
-
zoomXToEnd(zoomIn, zoomSensitivity
|
|
99
|
+
zoomXToEnd(zoomIn, zoomSensitivity) {
|
|
100
100
|
if (this.config.scale.disableAnimations) {
|
|
101
101
|
this.haltAnimation();
|
|
102
102
|
}
|
|
@@ -116,7 +116,7 @@ export class ScaleModel extends ViewportModel {
|
|
|
116
116
|
const initialStateCopy = Object.assign({}, state);
|
|
117
117
|
const constrainedState = this.scalePostProcessor(initialStateCopy, state);
|
|
118
118
|
if (this.state.lockPriceToBarRatio) {
|
|
119
|
-
|
|
119
|
+
changeYToKeepRatio(constrainedState, this.zoomXYRatio);
|
|
120
120
|
}
|
|
121
121
|
if (this.state.auto) {
|
|
122
122
|
this.autoScaleModel.doAutoYScale(constrainedState);
|
|
@@ -142,13 +142,31 @@ export class ScaleModel extends ViewportModel {
|
|
|
142
142
|
const state = this.export();
|
|
143
143
|
const constrainedState = this.scalePostProcessor(initialState, state);
|
|
144
144
|
if (this.state.lockPriceToBarRatio) {
|
|
145
|
-
|
|
145
|
+
changeYToKeepRatio(constrainedState, this.zoomXYRatio);
|
|
146
146
|
}
|
|
147
147
|
if (this.state.auto) {
|
|
148
148
|
this.autoScaleModel.doAutoYScale(constrainedState);
|
|
149
149
|
}
|
|
150
150
|
this.apply(constrainedState);
|
|
151
151
|
}
|
|
152
|
+
setYScale(yStart, yEnd, fire = false) {
|
|
153
|
+
const initialState = this.export();
|
|
154
|
+
super.setYScale(yStart, yEnd, fire);
|
|
155
|
+
const state = this.export();
|
|
156
|
+
const constrainedState = this.scalePostProcessor(initialState, state);
|
|
157
|
+
if (this.state.lockPriceToBarRatio) {
|
|
158
|
+
changeXToKeepRatio(constrainedState, this.zoomXYRatio);
|
|
159
|
+
this.setXScale(constrainedState.xStart, constrainedState.xEnd);
|
|
160
|
+
// TODO: rewrite logic for applying constraints to consider both axes, now constraints on Y may not work correctly
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
if (this.state.auto) {
|
|
165
|
+
this.autoScaleModel.doAutoYScale(constrainedState);
|
|
166
|
+
}
|
|
167
|
+
this.apply(constrainedState);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
152
170
|
/**
|
|
153
171
|
* Moves both xStart and xEnd without changing the viewport width (zoom).
|
|
154
172
|
* Works without animation.
|
|
@@ -32,7 +32,7 @@ export declare const candleEdgesConstrait: (state: ViewportModelState, visualCan
|
|
|
32
32
|
* @returns
|
|
33
33
|
* @doc-tags viewport,zoom,scaling
|
|
34
34
|
*/
|
|
35
|
-
export declare const zoomConstraint: (
|
|
35
|
+
export declare const zoomConstraint: (_: ViewportModelState, state: ViewportModelState, chartConfig: ChartConfigComponentsChart, boundsProvider: BoundsProvider) => {
|
|
36
36
|
xStart: number;
|
|
37
37
|
xEnd: number;
|
|
38
38
|
yStart: number;
|
|
@@ -40,7 +40,7 @@ export const candleEdgesConstrait = (state, visualCandlesCoordinates, candleLimi
|
|
|
40
40
|
* @returns
|
|
41
41
|
* @doc-tags viewport,zoom,scaling
|
|
42
42
|
*/
|
|
43
|
-
export const zoomConstraint = (
|
|
43
|
+
export const zoomConstraint = (_, state, chartConfig, boundsProvider) => {
|
|
44
44
|
const newState = Object.assign({}, state);
|
|
45
45
|
const bounds = boundsProvider();
|
|
46
46
|
// 1 - is an average candle width: newXEnd - newXStart = avg candles amount in the viewport
|
|
@@ -56,7 +56,6 @@ export const zoomConstraint = (initialState, state, chartConfig, boundsProvider)
|
|
|
56
56
|
return newState;
|
|
57
57
|
}
|
|
58
58
|
if (minViewportReached) {
|
|
59
|
-
newState.xEnd = initialState.xEnd;
|
|
60
59
|
newState.xStart = newState.xEnd - chartConfig.minCandles;
|
|
61
60
|
newState.zoomX = calculateZoom(newState.xEnd - newState.xStart, bounds.width);
|
|
62
61
|
return newState;
|
|
@@ -9,8 +9,14 @@ export declare const ratioFromZoomXY: (zoomX: Zoom, zoomY: Zoom) => ZoomXToZoomY
|
|
|
9
9
|
export declare const zoomXToZoomY: (zoomX: Zoom, ratio: ZoomXToZoomYRatio) => Zoom;
|
|
10
10
|
export declare const zoomYToZoomX: (zoomY: Zoom, ratio: ZoomXToZoomYRatio) => Zoom;
|
|
11
11
|
/**
|
|
12
|
-
* Locks the zoomY with zoomX and
|
|
12
|
+
* Locks the zoomY with zoomX and zooms y-scale depending on x-scale.
|
|
13
13
|
* @param state
|
|
14
14
|
* @param zoomXYRatio
|
|
15
15
|
*/
|
|
16
|
-
export declare const
|
|
16
|
+
export declare const changeYToKeepRatio: (state: ViewportModelState, zoomXYRatio: ZoomXToZoomYRatio) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Locks the zoomY with zoomX and zooms x-scale depending on y-scale.
|
|
19
|
+
* @param state
|
|
20
|
+
* @param zoomXYRatio
|
|
21
|
+
*/
|
|
22
|
+
export declare const changeXToKeepRatio: (state: ViewportModelState, zoomXYRatio: ZoomXToZoomYRatio) => void;
|
|
@@ -7,16 +7,31 @@ export const ratioFromZoomXY = (zoomX, zoomY) => zoomX / zoomY;
|
|
|
7
7
|
export const zoomXToZoomY = (zoomX, ratio) => zoomX / ratio;
|
|
8
8
|
export const zoomYToZoomX = (zoomY, ratio) => zoomY * ratio;
|
|
9
9
|
/**
|
|
10
|
-
* Locks the zoomY with zoomX and
|
|
10
|
+
* Locks the zoomY with zoomX and zooms y-scale depending on x-scale.
|
|
11
11
|
* @param state
|
|
12
12
|
* @param zoomXYRatio
|
|
13
13
|
*/
|
|
14
|
-
export const
|
|
14
|
+
export const changeYToKeepRatio = (state, zoomXYRatio) => {
|
|
15
15
|
const prevZoomY = state.zoomY;
|
|
16
16
|
state.zoomY = zoomXToZoomY(state.zoomX, zoomXYRatio);
|
|
17
17
|
const zoomYMult = state.zoomY / prevZoomY;
|
|
18
18
|
const lastYHeight = state.yEnd - state.yStart;
|
|
19
19
|
const newYHeight = lastYHeight * zoomYMult;
|
|
20
20
|
const delta = newYHeight - lastYHeight;
|
|
21
|
-
state.yEnd = state.yEnd + delta;
|
|
21
|
+
state.yEnd = state.yEnd + delta / 2;
|
|
22
|
+
state.yStart = state.yStart - delta / 2;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Locks the zoomY with zoomX and zooms x-scale depending on y-scale.
|
|
26
|
+
* @param state
|
|
27
|
+
* @param zoomXYRatio
|
|
28
|
+
*/
|
|
29
|
+
export const changeXToKeepRatio = (state, zoomXYRatio) => {
|
|
30
|
+
const prevZoomX = state.zoomX;
|
|
31
|
+
state.zoomX = zoomYToZoomX(state.zoomY, zoomXYRatio);
|
|
32
|
+
const zoomXMult = state.zoomX / prevZoomX;
|
|
33
|
+
const lastXWidth = state.xEnd - state.xStart;
|
|
34
|
+
const newXWidth = lastXWidth * zoomXMult;
|
|
35
|
+
const delta = newXWidth - lastXWidth;
|
|
36
|
+
state.xStart = state.xStart - delta;
|
|
22
37
|
};
|
|
@@ -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 {
|
|
6
|
+
import { PriceAxisType } from '../../components/labels_generator/numeric-axis-labels.generator';
|
|
7
7
|
export declare const isFirefox: boolean;
|
|
8
8
|
/**
|
|
9
9
|
* this function determines whether the event was triggered with the mouse or the touchpad
|
|
@@ -20,11 +20,11 @@ export declare const isFirefox: boolean;
|
|
|
20
20
|
*/
|
|
21
21
|
export declare const touchpadDetector: (e: WheelEvent) => boolean;
|
|
22
22
|
/**
|
|
23
|
-
* this function returns different
|
|
23
|
+
* this function returns different zoom sensitivity for the percent axis and the others
|
|
24
24
|
* @param config
|
|
25
25
|
* @param isTouchpad
|
|
26
26
|
* @returns {number}
|
|
27
27
|
*
|
|
28
28
|
* @doc-tags chart-core, zoom
|
|
29
29
|
*/
|
|
30
|
-
export declare const getTouchpadSensitivity: (
|
|
30
|
+
export declare const getTouchpadSensitivity: (type: PriceAxisType, zoomSensitivity: number) => number;
|
|
@@ -82,15 +82,13 @@ export const touchpadDetector = (e) => {
|
|
|
82
82
|
return isTouchpad;
|
|
83
83
|
};
|
|
84
84
|
/**
|
|
85
|
-
* this function returns different
|
|
85
|
+
* this function returns different zoom sensitivity for the percent axis and the others
|
|
86
86
|
* @param config
|
|
87
87
|
* @param isTouchpad
|
|
88
88
|
* @returns {number}
|
|
89
89
|
*
|
|
90
90
|
* @doc-tags chart-core, zoom
|
|
91
91
|
*/
|
|
92
|
-
export const getTouchpadSensitivity = (
|
|
93
|
-
|
|
94
|
-
const zoomSensitivity = isPercentAxisType ? config.scale.zoomSensitivity / 4 : config.scale.zoomSensitivity;
|
|
95
|
-
return zoomSensitivity;
|
|
92
|
+
export const getTouchpadSensitivity = (type, zoomSensitivity) => {
|
|
93
|
+
return type === 'percent' ? zoomSensitivity / 4 : zoomSensitivity;
|
|
96
94
|
};
|
|
@@ -3,7 +3,6 @@
|
|
|
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
|
-
export declare const MAX_DECIMAL_DIGITS = 14;
|
|
7
6
|
export type NumberFormatLabels = 'K' | 'M' | 'B';
|
|
8
7
|
export declare class MathUtils {
|
|
9
8
|
static roundToNearest(value: number, precision: number): number;
|