@devexperts/dxcharts-lite 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart/canvas/canvas-chart-html.js +7 -7
- package/dist/chart/components/pane/pane-hit-test.controller.js +1 -1
- package/dist/chart/components/volumes/volumes.component.d.ts +1 -1
- package/dist/chart/components/volumes/volumes.component.js +18 -11
- package/dist/chart/components/y_axis/y-axis.component.js +3 -1
- package/dist/chart/drawers/chart-type-drawers/area.drawer.js +1 -1
- package/dist/chart/drawers/data-series.drawer.js +1 -1
- package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +0 -2
- package/dist/chart/inputhandlers/main-canvas-touch.handler.js +0 -16
- package/dist/chart/model/data-series.model.d.ts +1 -1
- package/dist/chart/model/data-series.model.js +1 -1
- package/dist/chart/model/scale.model.d.ts +12 -8
- package/dist/chart/model/scale.model.js +35 -14
- package/dist/chart/model/scaling/constrait.functions.d.ts +1 -14
- package/dist/chart/model/scaling/constrait.functions.js +1 -29
- package/dist/dxchart.min.js +11 -11
- package/package.json +1 -1
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
export default (devexpertsPromoLink) => '<div data-element="chartResizer" style="position: relative; min-height: 20px; height: 100%; width: 100%; touch-action: manipulation; z-index: 0;">\n' +
|
|
7
7
|
'\t<div data-element="chartContainer" style="position: absolute; height: 100%; width: 100%;" class="chart chartArea--graph">\n' +
|
|
8
8
|
'\t\t<div data-element="canvasArea" style="position: relative; height: 100%; width: 100%; touch-action: manipulation;">\n' +
|
|
9
|
-
'\t\t\t<canvas data-element="snapshotCanvas"
|
|
10
|
-
'\t\t\t<canvas data-element="backgroundCanvas"
|
|
11
|
-
'\t\t\t<canvas data-element="mainCanvas"
|
|
12
|
-
'\t\t\t<canvas data-element="
|
|
13
|
-
'\t\t\t<canvas data-element="
|
|
14
|
-
'\t\t\t<canvas data-element="crossToolCanvas"
|
|
15
|
-
'\t\t\t<canvas data-element="hitTestCanvas"
|
|
9
|
+
'\t\t\t<canvas data-element="snapshotCanvas"></canvas>\n' +
|
|
10
|
+
'\t\t\t<canvas data-element="backgroundCanvas"></canvas>\n' +
|
|
11
|
+
'\t\t\t<canvas data-element="mainCanvas"></canvas>\n' +
|
|
12
|
+
'\t\t\t<canvas data-element="yAxisLabelsCanvas"></canvas>\n' +
|
|
13
|
+
'\t\t\t<canvas data-element="dynamicObjectsCanvas"></canvas>\n' +
|
|
14
|
+
'\t\t\t<canvas data-element="crossToolCanvas"></canvas>\n' +
|
|
15
|
+
'\t\t\t<canvas data-element="hitTestCanvas"></canvas>\n' +
|
|
16
16
|
`${devexpertsPromoLink
|
|
17
17
|
? '\t\t\t<p style="position: absolute; visibility: hidden;">If you have any suggestions or are experiencing any issues, please feel free to contact us at <a href="https://devexperts.com/dxcharts/">devexperts.com</a></p>\n'
|
|
18
18
|
: ''}` +
|
|
@@ -41,7 +41,7 @@ export class PaneHitTestController {
|
|
|
41
41
|
* @returns {void}
|
|
42
42
|
*/
|
|
43
43
|
onHover(model) {
|
|
44
|
-
this.allDataSeries.forEach(d => (d.
|
|
44
|
+
this.allDataSeries.forEach(d => (d.highlighted = d.htId === (model === null || model === void 0 ? void 0 : model.htId)));
|
|
45
45
|
this.canvasModel.fireDraw();
|
|
46
46
|
}
|
|
47
47
|
onMouseDown(model) {
|
|
@@ -25,7 +25,7 @@ export class VolumesComponent extends ChartBaseElement {
|
|
|
25
25
|
this.addChildEntity(volumesModel);
|
|
26
26
|
this.separateVolumes = new SeparateVolumesComponent(chartComponent, drawingManager, config, volumesModel, paneManager);
|
|
27
27
|
this.volumesDrawer = new VolumesDrawer(config, this.volumesModel, chartComponent.chartModel, () => { var _a, _b; return (this.config.components.volumes.showSeparately ? (_b = (_a = this.separateVolumes.pane) === null || _a === void 0 ? void 0 : _a.scale) !== null && _b !== void 0 ? _b : scale : scale); }, this.volumesColorByChartTypeMap, () => true);
|
|
28
|
-
config.components.volumes.visible && this.
|
|
28
|
+
config.components.volumes.visible && this.syncVolumesDynamicObject();
|
|
29
29
|
this.addChildEntity(this.separateVolumes);
|
|
30
30
|
this.registerDefaultVolumeColorResolvers();
|
|
31
31
|
this.volumeVisibilityChangedSubject.next(config.components.volumes.visible);
|
|
@@ -58,6 +58,7 @@ export class VolumesComponent extends ChartBaseElement {
|
|
|
58
58
|
this.separateVolumes.deactiveSeparateVolumes();
|
|
59
59
|
}
|
|
60
60
|
this.volumeIsSeparateModeChangedSubject.next(separate);
|
|
61
|
+
this.syncVolumesDynamicObject();
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
@@ -84,9 +85,6 @@ export class VolumesComponent extends ChartBaseElement {
|
|
|
84
85
|
setVisible(visible = true) {
|
|
85
86
|
this.config.components.volumes.visible = visible;
|
|
86
87
|
this.volumeVisibilityChangedSubject.next(visible);
|
|
87
|
-
visible
|
|
88
|
-
? this.addVolumesToDynamicObjects()
|
|
89
|
-
: this.dynamicObjectsComponent.model.removeObject(this.volumesModel.id);
|
|
90
88
|
if (this.config.components.volumes.showSeparately) {
|
|
91
89
|
if (visible) {
|
|
92
90
|
this.separateVolumes.activateSeparateVolumes();
|
|
@@ -98,19 +96,28 @@ export class VolumesComponent extends ChartBaseElement {
|
|
|
98
96
|
}
|
|
99
97
|
}
|
|
100
98
|
this.canvasBoundsContainer.recalculatePanesHeightRatios();
|
|
99
|
+
this.syncVolumesDynamicObject();
|
|
101
100
|
this.canvasModel.fireDraw();
|
|
102
101
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
syncVolumesDynamicObject() {
|
|
103
|
+
const visible = this.config.components.volumes.visible;
|
|
104
|
+
if (!visible) {
|
|
105
|
+
this.dynamicObjectsComponent.model.removeObject(this.volumesModel.id);
|
|
107
106
|
return;
|
|
108
107
|
}
|
|
109
|
-
this.
|
|
108
|
+
const paneId = this.config.components.volumes.showSeparately ? VOLUMES_UUID : CHART_UUID;
|
|
109
|
+
const volumesDynamicObject = {
|
|
110
110
|
id: this.volumesModel.id,
|
|
111
|
-
paneId
|
|
111
|
+
paneId,
|
|
112
112
|
drawer: this.volumesDrawer,
|
|
113
113
|
model: this.volumesModel,
|
|
114
|
-
}
|
|
114
|
+
};
|
|
115
|
+
// check if the volumes dynamic object is already added
|
|
116
|
+
const position = this.dynamicObjectsComponent.model.getObjectPosition(this.volumesModel.id);
|
|
117
|
+
if (position === -1) {
|
|
118
|
+
this.dynamicObjectsComponent.model.addObject(volumesDynamicObject);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
this.dynamicObjectsComponent.model.updateObject(volumesDynamicObject);
|
|
115
122
|
}
|
|
116
123
|
}
|
|
@@ -12,6 +12,7 @@ import { LabelsGroups } from './price_labels/y-axis-labels.model';
|
|
|
12
12
|
import { YAxisScaleHandler } from './y-axis-scale.handler';
|
|
13
13
|
import { YAxisModel } from './y-axis.model';
|
|
14
14
|
import { merge as mergeObj } from '../../utils/merge.utils';
|
|
15
|
+
import { cloneUnsafe } from '../../utils/object.utils';
|
|
15
16
|
/**
|
|
16
17
|
* Y axis component. Contains all Y axis related logic.
|
|
17
18
|
*/
|
|
@@ -28,7 +29,8 @@ export class YAxisComponent extends ChartBaseElement {
|
|
|
28
29
|
this.extentIdx = extentIdx;
|
|
29
30
|
this.labelsColorByChartTypeMap = {};
|
|
30
31
|
this.axisTypeSetSubject = new Subject();
|
|
31
|
-
|
|
32
|
+
const initialStateCopy = initialState ? cloneUnsafe(initialState) : {};
|
|
33
|
+
this.state = mergeObj(initialStateCopy, config.components.yAxis, {
|
|
32
34
|
overrideExisting: false,
|
|
33
35
|
addIfMissing: true,
|
|
34
36
|
});
|
|
@@ -47,7 +47,7 @@ export const setLineWidth = (ctx, lineWidth, dataSeries, drawerConfig, seriesSel
|
|
|
47
47
|
if (drawerConfig.forceBold) {
|
|
48
48
|
ctx.lineWidth = drawerConfig.forceBold;
|
|
49
49
|
}
|
|
50
|
-
else if (dataSeries.
|
|
50
|
+
else if (dataSeries.highlighted) {
|
|
51
51
|
ctx.lineWidth = lineWidth !== seriesSelectedWidth ? lineWidth + 1 : seriesSelectedWidth;
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
@@ -16,8 +16,6 @@ export declare class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
16
16
|
private canvasInputListeners;
|
|
17
17
|
private mainCanvasParent;
|
|
18
18
|
private touchedCandleIndexes;
|
|
19
|
-
private pinchDistance;
|
|
20
|
-
private isDraggable;
|
|
21
19
|
constructor(chartAreaPanHandler: ChartAreaPanHandler, scale: ScaleModel, canvasInputListeners: CanvasInputListenerComponent, mainCanvasParent: Element);
|
|
22
20
|
/**
|
|
23
21
|
* Activates canvas input listeners for touch start and touch move events.
|
|
@@ -4,7 +4,6 @@
|
|
|
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
|
-
const MIN_PINCH_DISTANCE = 30;
|
|
8
7
|
/**
|
|
9
8
|
* Handles chart touch events.
|
|
10
9
|
*/
|
|
@@ -17,10 +16,6 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
17
16
|
this.mainCanvasParent = mainCanvasParent;
|
|
18
17
|
// 2 candles indexes touched by 2 fingers when pinching
|
|
19
18
|
this.touchedCandleIndexes = [0, 0];
|
|
20
|
-
// number of px between touch events
|
|
21
|
-
this.pinchDistance = 0;
|
|
22
|
-
// used when maximum zoom in/out reached, can't use deactivate because it unsubscribes from all touch events
|
|
23
|
-
this.isDraggable = true;
|
|
24
19
|
}
|
|
25
20
|
/**
|
|
26
21
|
* Activates canvas input listeners for touch start and touch move events.
|
|
@@ -39,7 +34,6 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
39
34
|
*/
|
|
40
35
|
handleTouchStartEvent(e) {
|
|
41
36
|
if (e.touches.length === 2) {
|
|
42
|
-
this.isDraggable = true;
|
|
43
37
|
this.chartAreaPanHandler.deactivate();
|
|
44
38
|
// @ts-ignore
|
|
45
39
|
// TODO rework this
|
|
@@ -89,16 +83,6 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
|
|
|
89
83
|
* @returns {void}
|
|
90
84
|
*/
|
|
91
85
|
pinchHandler(candleIndexes, touchPositions) {
|
|
92
|
-
const diff = Math.abs(touchPositions[0]) - Math.abs(touchPositions[1]);
|
|
93
|
-
const pinchDistance = Math.abs(diff);
|
|
94
|
-
const zoomIn = pinchDistance > this.pinchDistance;
|
|
95
|
-
if (this.scale.isMaxZoomXReached(zoomIn)) {
|
|
96
|
-
this.isDraggable = false;
|
|
97
|
-
}
|
|
98
|
-
if (!this.isDraggable || pinchDistance < MIN_PINCH_DISTANCE) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
this.pinchDistance = pinchDistance;
|
|
102
86
|
const first = (touchPositions[0] * candleIndexes[1] - touchPositions[1] * candleIndexes[0]) /
|
|
103
87
|
(touchPositions[0] - touchPositions[1]);
|
|
104
88
|
const last = first +
|
|
@@ -48,7 +48,7 @@ export declare class DataSeriesModel<D extends DataSeriesPoint = DataSeriesPoint
|
|
|
48
48
|
id: string;
|
|
49
49
|
htId: number;
|
|
50
50
|
name: string;
|
|
51
|
-
|
|
51
|
+
highlighted: boolean;
|
|
52
52
|
yAxisLabelProvider: DataSeriesYAxisLabelsProvider;
|
|
53
53
|
readonly config: DataSeriesConfig;
|
|
54
54
|
scale: ScaleModel;
|
|
@@ -25,6 +25,10 @@ export interface ScaleHistoryItem {
|
|
|
25
25
|
export declare const getDefaultHighLowWithIndex: () => HighLowWithIndex;
|
|
26
26
|
export type ViewportPercent = number;
|
|
27
27
|
type Constraints = (initialState: ViewportModelState, state: ViewportModelState) => ViewportModelState;
|
|
28
|
+
export interface ZoomReached {
|
|
29
|
+
max: boolean;
|
|
30
|
+
min: boolean;
|
|
31
|
+
}
|
|
28
32
|
/**
|
|
29
33
|
* The ScaleModel class represents the state of a chart's scale, including the current viewport, zoom level, and auto-scaling settings.
|
|
30
34
|
* It extends the ViewportModel class, which provides the underlying implementation for handling viewports and zoom levels.
|
|
@@ -41,16 +45,13 @@ export declare class ScaleModel extends ViewportModel {
|
|
|
41
45
|
private canvasAnimation;
|
|
42
46
|
scaleInversedSubject: Subject<boolean>;
|
|
43
47
|
beforeStartAnimationSubject: Subject<void>;
|
|
44
|
-
history: ScaleHistoryItem[];
|
|
45
48
|
autoScaleModel: AutoScaleViewportSubModel;
|
|
46
49
|
zoomXYRatio: ZoomXToZoomYRatio;
|
|
47
|
-
|
|
48
|
-
xConstraints: Constraints[];
|
|
49
|
-
maxZoomReached: {
|
|
50
|
-
zoomIn: boolean;
|
|
51
|
-
zoomOut: boolean;
|
|
52
|
-
};
|
|
50
|
+
zoomReached: ZoomReached;
|
|
53
51
|
readonly state: ChartScale;
|
|
52
|
+
history: ScaleHistoryItem[];
|
|
53
|
+
offsets: ChartConfigComponentsOffsets;
|
|
54
|
+
private xConstraints;
|
|
54
55
|
constructor(config: FullChartConfig, getBounds: BoundsProvider, canvasAnimation: CanvasAnimation);
|
|
55
56
|
protected doActivate(): void;
|
|
56
57
|
protected doDeactivate(): void;
|
|
@@ -86,7 +87,10 @@ export declare class ScaleModel extends ViewportModel {
|
|
|
86
87
|
zoomXToEnd(zoomIn: boolean, zoomSensitivity: number): void;
|
|
87
88
|
haltAnimation(): void;
|
|
88
89
|
private zoomXTo;
|
|
89
|
-
|
|
90
|
+
calculateZoomReached(zoomX: Unit, zoomIn?: boolean): {
|
|
91
|
+
max: boolean;
|
|
92
|
+
min: boolean;
|
|
93
|
+
};
|
|
90
94
|
/**
|
|
91
95
|
* Moves the viewport to exactly xStart..xEnd place.
|
|
92
96
|
* (you need to fire DRAW event after this)
|
|
@@ -7,10 +7,9 @@ import { Subject } from 'rxjs';
|
|
|
7
7
|
import { startViewportModelAnimation } from '../animation/viewport-model-animation';
|
|
8
8
|
import { cloneUnsafe } from '../utils/object.utils';
|
|
9
9
|
import { AutoScaleViewportSubModel } from './scaling/auto-scale.model';
|
|
10
|
-
import { zoomConstraint } from './scaling/constrait.functions';
|
|
11
10
|
import { changeXToKeepRatio, changeYToKeepRatio, ratioFromZoomXY } from './scaling/lock-ratio.model';
|
|
12
11
|
import { moveXStart, moveYStart } from './scaling/move-chart.functions';
|
|
13
|
-
import { ViewportModel, compareStates } from './scaling/viewport.model';
|
|
12
|
+
import { ViewportModel, calculateZoom, compareStates, } from './scaling/viewport.model';
|
|
14
13
|
import { zoomXToEndViewportCalculator, zoomXToPercentViewportCalculator } from './scaling/x-zooming.functions';
|
|
15
14
|
export const getDefaultHighLowWithIndex = () => ({
|
|
16
15
|
high: Number.NEGATIVE_INFINITY,
|
|
@@ -37,11 +36,11 @@ export class ScaleModel extends ViewportModel {
|
|
|
37
36
|
this.scaleInversedSubject = new Subject();
|
|
38
37
|
// y-axis component needs this subject in order to halt prev animation if axis type is percent
|
|
39
38
|
this.beforeStartAnimationSubject = new Subject();
|
|
39
|
+
this.zoomXYRatio = 0;
|
|
40
|
+
this.zoomReached = { min: false, max: false };
|
|
40
41
|
// TODO rework, make a new history based on units
|
|
41
42
|
this.history = [];
|
|
42
|
-
this.zoomXYRatio = 0;
|
|
43
43
|
this.xConstraints = [];
|
|
44
|
-
this.maxZoomReached = { zoomIn: false, zoomOut: false };
|
|
45
44
|
this.scalePostProcessor = (initialState, state) => {
|
|
46
45
|
// for now <s>reduceRight<s/> reduce bcs ChartModel#getZoomConstrait should be invoked first
|
|
47
46
|
// if we will need more complex order handling -> add some managing
|
|
@@ -50,16 +49,12 @@ export class ScaleModel extends ViewportModel {
|
|
|
50
49
|
this.state = cloneUnsafe(config.scale);
|
|
51
50
|
this.autoScaleModel = new AutoScaleViewportSubModel(this);
|
|
52
51
|
this.offsets = this.config.components.offsets;
|
|
53
|
-
this.addXConstraint((initialState, state) => {
|
|
54
|
-
const { maxZoomReached, newState } = zoomConstraint(initialState, state, this.config.components.chart, this.getBounds);
|
|
55
|
-
this.maxZoomReached = maxZoomReached;
|
|
56
|
-
return newState;
|
|
57
|
-
});
|
|
58
52
|
}
|
|
59
53
|
doActivate() {
|
|
60
54
|
super.doActivate();
|
|
61
55
|
this.scaleInversedSubject = new Subject();
|
|
62
56
|
this.beforeStartAnimationSubject = new Subject();
|
|
57
|
+
this.zoomReached = this.calculateZoomReached(this.export().zoomX);
|
|
63
58
|
this.addRxSubscription(this.scaleInversedSubject.subscribe(() => {
|
|
64
59
|
this.fireChanged();
|
|
65
60
|
}));
|
|
@@ -107,7 +102,7 @@ export class ScaleModel extends ViewportModel {
|
|
|
107
102
|
this.beforeStartAnimationSubject.next();
|
|
108
103
|
const state = this.export();
|
|
109
104
|
zoomXToPercentViewportCalculator(this, state, viewportPercent, zoomSensitivity, zoomIn);
|
|
110
|
-
this.zoomXTo(state, disabledAnimations);
|
|
105
|
+
this.zoomXTo(state, zoomIn, disabledAnimations);
|
|
111
106
|
}
|
|
112
107
|
/**
|
|
113
108
|
* Zooms the X axis of the chart relativly to the end of the data range.
|
|
@@ -121,7 +116,7 @@ export class ScaleModel extends ViewportModel {
|
|
|
121
116
|
this.beforeStartAnimationSubject.next();
|
|
122
117
|
const state = this.export();
|
|
123
118
|
zoomXToEndViewportCalculator(this, state, zoomSensitivity, zoomIn);
|
|
124
|
-
this.zoomXTo(state, this.config.scale.disableAnimations);
|
|
119
|
+
this.zoomXTo(state, zoomIn, this.config.scale.disableAnimations);
|
|
125
120
|
}
|
|
126
121
|
haltAnimation() {
|
|
127
122
|
var _a;
|
|
@@ -130,9 +125,13 @@ export class ScaleModel extends ViewportModel {
|
|
|
130
125
|
this.doAutoScale();
|
|
131
126
|
}
|
|
132
127
|
}
|
|
133
|
-
zoomXTo(state, forceNoAnimation) {
|
|
128
|
+
zoomXTo(state, zoomIn, forceNoAnimation) {
|
|
134
129
|
const initialStateCopy = Object.assign({}, state);
|
|
135
130
|
const constrainedState = this.scalePostProcessor(initialStateCopy, state);
|
|
131
|
+
this.zoomReached = this.calculateZoomReached(constrainedState.zoomX, zoomIn);
|
|
132
|
+
if (this.zoomReached.max || this.zoomReached.min) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
136
135
|
if (this.state.lockPriceToBarRatio) {
|
|
137
136
|
changeYToKeepRatio(constrainedState, this.zoomXYRatio);
|
|
138
137
|
}
|
|
@@ -146,8 +145,19 @@ export class ScaleModel extends ViewportModel {
|
|
|
146
145
|
startViewportModelAnimation(this.canvasAnimation, this, constrainedState);
|
|
147
146
|
}
|
|
148
147
|
}
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
calculateZoomReached(zoomX, zoomIn = true) {
|
|
149
|
+
const chartWidth = this.getBounds().width;
|
|
150
|
+
const delta = 0.001; // zoom values are very precise and should be compared with some precision delta
|
|
151
|
+
if (chartWidth > 0) {
|
|
152
|
+
const maxZoomReached = zoomX - calculateZoom(this.config.components.chart.minCandles, chartWidth) <= delta;
|
|
153
|
+
// max zoom reached and trying to zoom in further
|
|
154
|
+
const maxZoomDisabled = maxZoomReached && zoomIn;
|
|
155
|
+
const minZoomReached = zoomX - calculateZoom(chartWidth / this.config.components.chart.minWidth, chartWidth) >= delta;
|
|
156
|
+
// min zoom reached and trying to zoom out further
|
|
157
|
+
const minZoomDisabled = minZoomReached && !zoomIn;
|
|
158
|
+
return { max: maxZoomDisabled, min: minZoomDisabled };
|
|
159
|
+
}
|
|
160
|
+
return { max: false, min: false };
|
|
151
161
|
}
|
|
152
162
|
/**
|
|
153
163
|
* Moves the viewport to exactly xStart..xEnd place.
|
|
@@ -160,8 +170,16 @@ export class ScaleModel extends ViewportModel {
|
|
|
160
170
|
setXScale(xStart, xEnd, forceNoAnimation = true) {
|
|
161
171
|
const initialState = this.export();
|
|
162
172
|
const zoomX = this.calculateZoomX(xStart, xEnd);
|
|
173
|
+
if (initialState.xStart === xStart && initialState.xEnd === xEnd && initialState.zoomX > 0) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
163
176
|
const state = Object.assign(Object.assign({}, initialState), { zoomX, xStart, xEnd });
|
|
164
177
|
const constrainedState = this.scalePostProcessor(initialState, state);
|
|
178
|
+
const zoomIn = constrainedState.xEnd - constrainedState.xStart < initialState.xEnd - initialState.xStart;
|
|
179
|
+
this.zoomReached = this.calculateZoomReached(zoomX, zoomIn);
|
|
180
|
+
if (this.zoomReached.max || this.zoomReached.min) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
165
183
|
if (this.state.lockPriceToBarRatio) {
|
|
166
184
|
changeYToKeepRatio(constrainedState, this.zoomXYRatio);
|
|
167
185
|
}
|
|
@@ -178,6 +196,9 @@ export class ScaleModel extends ViewportModel {
|
|
|
178
196
|
}
|
|
179
197
|
setYScale(yStart, yEnd, fire = false) {
|
|
180
198
|
const initialState = this.export();
|
|
199
|
+
if (initialState.yStart === yStart && initialState.yEnd === yEnd && initialState.zoomY > 0) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
181
202
|
super.setYScale(yStart, yEnd, fire);
|
|
182
203
|
const state = this.export();
|
|
183
204
|
const constrainedState = this.scalePostProcessor(initialState, state);
|
|
@@ -3,8 +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 {
|
|
7
|
-
import { Bounds, BoundsProvider } from '../bounds.model';
|
|
6
|
+
import { Bounds } from '../bounds.model';
|
|
8
7
|
import VisualCandle from '../visual-candle';
|
|
9
8
|
import { ViewportModelState } from './viewport.model';
|
|
10
9
|
/**
|
|
@@ -27,15 +26,3 @@ export declare const candleEdgesConstrait: (state: ViewportModelState, visualCan
|
|
|
27
26
|
zoomY: number;
|
|
28
27
|
inverseY: boolean;
|
|
29
28
|
};
|
|
30
|
-
/**
|
|
31
|
-
* This function limits minimum and maximum chart viewport dependening on visible x-units
|
|
32
|
-
* @returns
|
|
33
|
-
* @doc-tags viewport,zoom,scaling
|
|
34
|
-
*/
|
|
35
|
-
export declare const zoomConstraint: (_: ViewportModelState, state: ViewportModelState, chartConfig: ChartConfigComponentsChart, boundsProvider: BoundsProvider) => {
|
|
36
|
-
newState: ViewportModelState;
|
|
37
|
-
maxZoomReached: {
|
|
38
|
-
zoomIn: boolean;
|
|
39
|
-
zoomOut: boolean;
|
|
40
|
-
};
|
|
41
|
-
};
|
|
@@ -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 { at } from '../../utils/array.utils';
|
|
7
|
-
import {
|
|
7
|
+
import { pixelsToUnits } from './viewport.model';
|
|
8
8
|
/**
|
|
9
9
|
* Return constraited state that handled zooming and moving chart near first/last candles
|
|
10
10
|
* this and other constraits that works with state should mutate and return state
|
|
@@ -35,31 +35,3 @@ export const candleEdgesConstrait = (state, visualCandlesCoordinates, candleLimi
|
|
|
35
35
|
newState.xEnd = normalizedXEnd;
|
|
36
36
|
return newState;
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
39
|
-
* This function limits minimum and maximum chart viewport dependening on visible x-units
|
|
40
|
-
* @returns
|
|
41
|
-
* @doc-tags viewport,zoom,scaling
|
|
42
|
-
*/
|
|
43
|
-
export const zoomConstraint = (_, state, chartConfig, boundsProvider) => {
|
|
44
|
-
const newState = Object.assign({}, state);
|
|
45
|
-
const bounds = boundsProvider();
|
|
46
|
-
// 1 - is an average candle width: newXEnd - newXStart = avg candles amount in the viewport
|
|
47
|
-
const avgCandlesInViewport = newState.xEnd - newState.xStart;
|
|
48
|
-
const minViewportReached = avgCandlesInViewport < chartConfig.minCandles;
|
|
49
|
-
const maxCandlesInViewport = bounds.width / chartConfig.minWidth;
|
|
50
|
-
const maxViewportReached = avgCandlesInViewport > maxCandlesInViewport;
|
|
51
|
-
// rules work only if chart is shown
|
|
52
|
-
if (bounds.width > 0) {
|
|
53
|
-
if (maxViewportReached) {
|
|
54
|
-
newState.xStart = newState.xEnd - maxCandlesInViewport;
|
|
55
|
-
newState.zoomX = calculateZoom(newState.xEnd - newState.xStart, bounds.width);
|
|
56
|
-
return { newState, maxZoomReached: { zoomOut: true, zoomIn: false } };
|
|
57
|
-
}
|
|
58
|
-
if (minViewportReached) {
|
|
59
|
-
newState.xStart = newState.xEnd - chartConfig.minCandles;
|
|
60
|
-
newState.zoomX = calculateZoom(newState.xEnd - newState.xStart, bounds.width);
|
|
61
|
-
return { newState, maxZoomReached: { zoomOut: false, zoomIn: true } };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return { newState, maxZoomReached: { zoomOut: false, zoomIn: false } };
|
|
65
|
-
};
|