@devexperts/dxcharts-lite 2.0.1 → 2.1.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/README.md +28 -29
- package/dist/chart/__tests__/chart.test.d.ts +6 -0
- package/dist/chart/__tests__/chart.test.js +51 -0
- package/dist/chart/{chart-container.js → __tests__/env.d.ts} +0 -1
- package/dist/chart/__tests__/env.js +28 -0
- package/dist/chart/bootstrap.d.ts +7 -2
- package/dist/chart/bootstrap.js +2 -2
- package/dist/chart/chart.config.d.ts +4 -1
- package/dist/chart/chart.config.js +1 -1
- package/dist/chart/chart.d.ts +2 -0
- package/dist/chart/chart.js +3 -1
- package/dist/chart/components/chart/candle-transformer.functions.d.ts +1 -0
- package/dist/chart/components/chart/candle-transformer.functions.js +1 -0
- package/dist/chart/components/chart/chart-base.model.d.ts +2 -2
- package/dist/chart/components/chart/chart-base.model.js +2 -2
- package/dist/chart/components/chart/chart.component.d.ts +6 -0
- package/dist/chart/components/chart/chart.component.js +23 -4
- package/dist/chart/components/chart/chart.model.d.ts +9 -3
- package/dist/chart/components/chart/chart.model.js +35 -13
- package/dist/chart/components/cross_tool/cross-tool.component.d.ts +2 -1
- package/dist/chart/components/cross_tool/cross-tool.component.js +4 -3
- package/dist/chart/components/cross_tool/cross-tool.model.js +1 -0
- package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.d.ts +3 -1
- package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +3 -2
- package/dist/chart/components/dynamic-objects/dynamic-objects.component.js +1 -1
- package/dist/chart/components/dynamic-objects/dynamic-objects.model.d.ts +30 -10
- package/dist/chart/components/dynamic-objects/dynamic-objects.model.js +119 -57
- package/dist/chart/components/grid/grid.drawer.js +3 -1
- package/dist/chart/components/pane/extent/y-extent-component.js +2 -1
- package/dist/chart/components/pane/pane-hit-test.controller.js +2 -2
- package/dist/chart/components/volumes/volumes.component.d.ts +3 -0
- package/dist/chart/components/volumes/volumes.component.js +21 -4
- package/dist/chart/components/volumes/volumes.model.d.ts +2 -0
- package/dist/chart/components/volumes/volumes.model.js +2 -0
- package/dist/chart/components/x_axis/x-axis.component.js +2 -2
- package/dist/chart/components/y_axis/label-color.functions.d.ts +2 -1
- package/dist/chart/components/y_axis/label-color.functions.js +17 -0
- package/dist/chart/components/y_axis/price_labels/data-series-y-axis-labels.provider.d.ts +2 -2
- package/dist/chart/components/y_axis/price_labels/data-series-y-axis-labels.provider.js +27 -25
- package/dist/chart/components/y_axis/price_labels/labels-positions-calculator.js +24 -13
- package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.d.ts +3 -3
- package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.js +58 -40
- package/dist/chart/components/y_axis/price_labels/y-axis-price-labels.drawer.d.ts +3 -3
- package/dist/chart/components/y_axis/price_labels/y-axis-price-labels.drawer.js +15 -13
- package/dist/chart/components/y_axis/y-axis-scale.handler.js +1 -1
- package/dist/chart/components/y_axis/y-axis.component.d.ts +2 -1
- package/dist/chart/components/y_axis/y-axis.component.js +6 -2
- package/dist/chart/drawers/ht-data-series.drawer.js +1 -1
- package/dist/chart/inputhandlers/hover-producer.component.d.ts +1 -1
- package/dist/chart/inputhandlers/hover-producer.component.js +7 -7
- package/dist/chart/inputlisteners/canvas-input-listener.component.d.ts +9 -2
- package/dist/chart/inputlisteners/canvas-input-listener.component.js +21 -19
- package/dist/chart/model/candle-series.model.d.ts +1 -1
- package/dist/chart/model/candle-series.model.js +2 -2
- package/dist/chart/model/compare-series-hover.d.ts +2 -1
- package/dist/chart/model/compare-series-hover.js +1 -0
- package/dist/chart/model/data-series.model.d.ts +3 -2
- package/dist/chart/model/data-series.model.js +2 -1
- package/dist/chart/model/main-candle-series.model.d.ts +1 -1
- package/dist/chart/model/main-candle-series.model.js +2 -2
- package/dist/chart/model/scale.model.d.ts +2 -0
- package/dist/chart/model/scale.model.js +11 -2
- package/dist/chart/utils/dom.utils.d.ts +7 -0
- package/dist/chart/utils/dom.utils.js +12 -0
- package/dist/chart/utils/linkedList.utils.d.ts +3 -3
- package/dist/chart/utils/linkedList.utils.js +55 -57
- package/dist/dxchart.min.js +4 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -8
- package/package.json +18 -4
- package/dist/chart/chart-container.d.ts +0 -18
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
<img src="https://img.shields.io/static/v1?label=PRs&message=Welcome&color=blue" alt="PRs: Welcome" />
|
|
24
24
|
</a>
|
|
25
25
|
<a href="https://devexperts.com/dxcharts-demo/?lang=en">
|
|
26
|
-
<img src="https://img.shields.io/static/v1?label=Latest%20version&message=1.0
|
|
26
|
+
<img src="https://img.shields.io/static/v1?label=Latest%20version&message=2.1.0&color=blue" alt="Version" />
|
|
27
27
|
</a>
|
|
28
28
|
</p>
|
|
29
29
|
|
|
@@ -97,16 +97,11 @@ Now you should have empty chart on screen.
|
|
|
97
97
|
|
|
98
98
|
Let's pass in some data i.e. `Candles`. You can use bundled function to generate some mock data.
|
|
99
99
|
Import `generateCandlesData` and call it to generate candles.
|
|
100
|
-
Also, you would need `Instrument` object - it is required to show instrument description on chart and show correct price precisions on Y axis.
|
|
101
100
|
|
|
102
101
|
```js
|
|
103
102
|
export const generateMockData = () => {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
symbol: 'AAPL',
|
|
107
|
-
priceIncrements: [0.01],
|
|
108
|
-
};
|
|
109
|
-
chart.setData({ candles: mockCandles, instrument: mockInstrument });
|
|
103
|
+
const candles = generateCandlesData();
|
|
104
|
+
chart.setData({ candles });
|
|
110
105
|
};
|
|
111
106
|
```
|
|
112
107
|
|
|
@@ -120,28 +115,32 @@ Now you should see chart just like image below:
|
|
|
120
115
|
|
|
121
116
|
Here is full quick-start code example:
|
|
122
117
|
|
|
123
|
-
```
|
|
118
|
+
```html
|
|
124
119
|
<html>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
120
|
+
<head>
|
|
121
|
+
<script src="https://www.unpkg.com/@devexperts/dxcharts-lite@2.0.1/dist/dxchart.min.js"></script>
|
|
122
|
+
<script type="importmap">
|
|
123
|
+
{
|
|
124
|
+
"imports": {
|
|
125
|
+
"@devexperts/dxcharts-lite/": "https://www.unpkg.com/@devexperts/dxcharts-lite@2.0.1/"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
</script>
|
|
129
|
+
</head>
|
|
130
|
+
<body>
|
|
131
|
+
<div id="chart_container"></div>
|
|
132
|
+
</body>
|
|
133
|
+
<script type="module">
|
|
134
|
+
import generateCandlesData from '@devexperts/dxcharts-lite/dist/chart/utils/candles-generator.utils';
|
|
135
|
+
|
|
136
|
+
// create chart instance, pass parent container as 1st argument
|
|
137
|
+
const container = document.getElementById('chart_container');
|
|
138
|
+
const chart = DXChart.createChart(container);
|
|
139
|
+
// create and set candles data
|
|
140
|
+
const candles = generateCandlesData();
|
|
141
|
+
chart.setData({ candles });
|
|
142
|
+
</script>
|
|
143
|
+
</html>
|
|
145
144
|
```
|
|
146
145
|
|
|
147
146
|
## Configuration
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2019 - 2023 Devexperts Solutions IE Limited
|
|
3
|
+
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
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
|
+
*/
|
|
6
|
+
import './env';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2019 - 2023 Devexperts Solutions IE Limited
|
|
3
|
+
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
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
|
+
*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
import './env';
|
|
16
|
+
import { createChart } from '../../index';
|
|
17
|
+
import { generateCandlesDataTS } from '../utils/candles-generator-ts.utils';
|
|
18
|
+
describe('chart', () => {
|
|
19
|
+
const candles = generateCandlesDataTS({ quantity: 50 });
|
|
20
|
+
it.each([
|
|
21
|
+
['zero -> non-zero candles', [[], candles]],
|
|
22
|
+
['prepend candles', [candles.slice(10), candles.slice(0, 10)]],
|
|
23
|
+
['prepend with a gap', [candles.slice(0, 10), candles.slice(20, 30)]],
|
|
24
|
+
['prepend with overlap', [candles.slice(10), candles.slice(0, 20)]],
|
|
25
|
+
['prepend with full overlap', [candles.slice(10), candles]],
|
|
26
|
+
['only update existing candles', [candles, candles.slice(10, 20)]],
|
|
27
|
+
['update all candles', [candles, candles]],
|
|
28
|
+
['append candles', [candles.slice(0, 10), candles.slice(10)]],
|
|
29
|
+
['append candles with a gap', [candles.slice(0, 10), candles.slice(20)]],
|
|
30
|
+
['append candles with overlap', [candles.slice(0, 20), candles.slice(10)]],
|
|
31
|
+
['append candles with full overlap', [candles.slice(0, 20), candles]],
|
|
32
|
+
['prepend and append', [candles.slice(10, 20), candles.slice(0, 30)]],
|
|
33
|
+
[
|
|
34
|
+
"fill in the gap (won't work but should not error)",
|
|
35
|
+
[candles.slice(0, 10), candles.slice(11, 20), candles.slice(10, 11)],
|
|
36
|
+
],
|
|
37
|
+
])('should update candles in various scenarios: %s', (scenario, updates) => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
+
const div = document.createElement('div');
|
|
39
|
+
const chart = createChart(div);
|
|
40
|
+
updates.forEach((update, i) => {
|
|
41
|
+
if (i === 0) {
|
|
42
|
+
chart.setData({ candles: update });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
chart.updateData({ candles: update });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
// wait for async tasks to complete successfully
|
|
49
|
+
yield new Promise(done => setTimeout(done, 100));
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2019 - 2023 Devexperts Solutions IE Limited
|
|
3
|
+
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
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
|
+
*/
|
|
6
|
+
"use strict";
|
|
7
|
+
/* @see https://jestjs.io/docs/29.4/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom */
|
|
8
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
9
|
+
writable: true,
|
|
10
|
+
value: jest.fn().mockImplementation(query => ({
|
|
11
|
+
matches: false,
|
|
12
|
+
media: query,
|
|
13
|
+
onchange: null,
|
|
14
|
+
addListener: jest.fn(),
|
|
15
|
+
removeListener: jest.fn(),
|
|
16
|
+
addEventListener: jest.fn(),
|
|
17
|
+
removeEventListener: jest.fn(),
|
|
18
|
+
dispatchEvent: jest.fn(),
|
|
19
|
+
})),
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(window, 'ResizeObserver', {
|
|
22
|
+
writable: true,
|
|
23
|
+
value: jest.fn().mockImplementation(() => ({
|
|
24
|
+
observe: jest.fn(),
|
|
25
|
+
unobserve: jest.fn(),
|
|
26
|
+
disconnect: jest.fn(),
|
|
27
|
+
})),
|
|
28
|
+
});
|
|
@@ -7,7 +7,6 @@ import { CanvasAnimation } from './animation/canvas-animation';
|
|
|
7
7
|
import { CanvasBoundsContainer } from './canvas/canvas-bounds-container';
|
|
8
8
|
import { ValidatedChartElements } from './canvas/chart-elements';
|
|
9
9
|
import { CursorHandler } from './canvas/cursor.handler';
|
|
10
|
-
import ChartContainer from './chart-container';
|
|
11
10
|
import { ChartColors, ChartConfigComponentsOffsets, FullChartConfig, GridComponentConfig, PartialChartConfig } from './chart.config';
|
|
12
11
|
import { ChartBaseModel } from './components/chart/chart-base.model';
|
|
13
12
|
import { ChartComponent } from './components/chart/chart.component';
|
|
@@ -43,7 +42,7 @@ export type FitType = 'studies' | 'orders' | 'positions';
|
|
|
43
42
|
/**
|
|
44
43
|
* @deprecated use {Chart} instead
|
|
45
44
|
*/
|
|
46
|
-
export default class ChartBootstrap
|
|
45
|
+
export default class ChartBootstrap {
|
|
47
46
|
id: string;
|
|
48
47
|
bus: EventBus;
|
|
49
48
|
config: FullChartConfig;
|
|
@@ -89,6 +88,9 @@ export default class ChartBootstrap implements ChartContainer {
|
|
|
89
88
|
mainCanvasModel: CanvasModel;
|
|
90
89
|
dynamicObjectsCanvasModel: CanvasModel;
|
|
91
90
|
hitTestCanvasModel: HitTestCanvasModel;
|
|
91
|
+
/**
|
|
92
|
+
* @deprecated use {bounds} instead
|
|
93
|
+
*/
|
|
92
94
|
canvasBoundsContainer: CanvasBoundsContainer;
|
|
93
95
|
canvasInputListener: CanvasInputListenerComponent;
|
|
94
96
|
/**
|
|
@@ -117,6 +119,9 @@ export default class ChartBootstrap implements ChartContainer {
|
|
|
117
119
|
*/
|
|
118
120
|
chartPanComponent: ChartPanComponent;
|
|
119
121
|
paneManager: PaneManager;
|
|
122
|
+
/**
|
|
123
|
+
* @deprecated use {hover} instead
|
|
124
|
+
*/
|
|
120
125
|
hoverProducer: HoverProducerComponent;
|
|
121
126
|
canvasModels: CanvasModel[];
|
|
122
127
|
chartResizeHandler: ChartResizeHandler;
|
package/dist/chart/bootstrap.js
CHANGED
|
@@ -179,7 +179,7 @@ export default class ChartBootstrap {
|
|
|
179
179
|
this.chartComponents.push(mainChartGridComponent);
|
|
180
180
|
this.hoverProducer = new HoverProducerComponent(this.crossEventProducer, scaleModel, config, chartModel, canvasInputListener, this.canvasBoundsContainer, this.paneManager, timeZoneModel, formatterFactory);
|
|
181
181
|
this.chartComponents.push(this.hoverProducer);
|
|
182
|
-
this.crossToolComponent = new CrossToolComponent(config, crossToolCanvasModel, canvasBoundsContainer, drawingManager, paneManager, this.crossEventProducer, this.hoverProducer);
|
|
182
|
+
this.crossToolComponent = new CrossToolComponent(config, crossToolCanvasModel, canvasBoundsContainer, drawingManager, paneManager, this.crossEventProducer, this.hoverProducer, this.backgroundCanvasModel);
|
|
183
183
|
this.chartComponents.push(this.crossToolComponent);
|
|
184
184
|
// Snapshot component
|
|
185
185
|
const snapshotCanvasModel = createCanvasModel(eventBus, elements.snapshotCanvas, config, drawingManager, this.canvasModels, elements.chartResizer);
|
|
@@ -203,7 +203,7 @@ export default class ChartBootstrap {
|
|
|
203
203
|
this.drawingManager.addDrawer(yAxisCompositeDrawer, 'Y_AXIS');
|
|
204
204
|
const yAxisDrawer = new YAxisDrawer(this.config, yAxisLabelsCanvasModel, this.paneManager);
|
|
205
205
|
yAxisCompositeDrawer.addDrawer(yAxisDrawer);
|
|
206
|
-
const yAxisLabelsDrawer = new YAxisPriceLabelsDrawer(yAxisLabelsCanvasModel, this.backgroundCanvasModel, this.canvasBoundsContainer, this.config
|
|
206
|
+
const yAxisLabelsDrawer = new YAxisPriceLabelsDrawer(yAxisLabelsCanvasModel, this.backgroundCanvasModel, this.canvasBoundsContainer, this.config, this.paneManager);
|
|
207
207
|
yAxisCompositeDrawer.addDrawer(yAxisLabelsDrawer);
|
|
208
208
|
}
|
|
209
209
|
// TODO remove chartModel dependency, put period to global config somewhere
|
|
@@ -106,7 +106,6 @@ export interface FullChartColors {
|
|
|
106
106
|
};
|
|
107
107
|
yAxis: {
|
|
108
108
|
backgroundColor: string;
|
|
109
|
-
backgroundHoverColor: string;
|
|
110
109
|
zeroPercentLine: string;
|
|
111
110
|
labelTextColor: string;
|
|
112
111
|
labelInvertedTextColor: string;
|
|
@@ -246,6 +245,10 @@ export interface ChartScale {
|
|
|
246
245
|
* Adjust x viewport when y-axis width is changed, so x zoom remains the same
|
|
247
246
|
*/
|
|
248
247
|
keepZoomXOnYAxisChange: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Disable all scale process animations
|
|
250
|
+
*/
|
|
251
|
+
disableAnimations: boolean;
|
|
249
252
|
}
|
|
250
253
|
export interface AutoScaleDisableOnDrag {
|
|
251
254
|
enabled: boolean;
|
|
@@ -43,6 +43,7 @@ export const getDefaultConfig = () => ({
|
|
|
43
43
|
inverse: false,
|
|
44
44
|
zoomSensitivity: 0.25,
|
|
45
45
|
defaultViewportItems: 100,
|
|
46
|
+
disableAnimations: false
|
|
46
47
|
},
|
|
47
48
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
48
49
|
components: {
|
|
@@ -455,7 +456,6 @@ export const getDefaultConfig = () => ({
|
|
|
455
456
|
],
|
|
456
457
|
yAxis: {
|
|
457
458
|
backgroundColor: 'transparent',
|
|
458
|
-
backgroundHoverColor: 'rgba(20,20,19,1)',
|
|
459
459
|
labelBoxColor: 'rgba(20,20,19,1)',
|
|
460
460
|
labelTextColor: 'rgba(128,128,128,1)',
|
|
461
461
|
labelInvertedTextColor: 'rgba(20,20,19,1)',
|
package/dist/chart/chart.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare class Chart extends ChartBootstrap {
|
|
|
24
24
|
data: import("./components/chart/chart.component").ChartComponent;
|
|
25
25
|
scale: import("./model/scale.model").ScaleModel;
|
|
26
26
|
panning: import("./components/pan/chart-pan.component").ChartPanComponent;
|
|
27
|
+
bounds: import("./canvas/canvas-bounds-container").CanvasBoundsContainer;
|
|
28
|
+
hover: import("./inputhandlers/hover-producer.component").HoverProducerComponent;
|
|
27
29
|
constructor(element: HTMLElement, config?: PartialChartConfig);
|
|
28
30
|
/**
|
|
29
31
|
* Registers number formatters for pane
|
package/dist/chart/chart.js
CHANGED
|
@@ -23,6 +23,8 @@ export class Chart extends ChartBootstrap {
|
|
|
23
23
|
this.data = this.chartComponent;
|
|
24
24
|
this.scale = this.scaleModel;
|
|
25
25
|
this.panning = this.chartPanComponent;
|
|
26
|
+
this.bounds = this.canvasBoundsContainer;
|
|
27
|
+
this.hover = this.hoverProducer;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Registers number formatters for pane
|
|
@@ -53,7 +55,7 @@ export class Chart extends ChartBootstrap {
|
|
|
53
55
|
showSeparateVolumes(separate = false) {
|
|
54
56
|
if (this.volumes) {
|
|
55
57
|
this.volumes.setShowVolumesSeparatly(separate);
|
|
56
|
-
this.
|
|
58
|
+
this.bounds.updateYAxisWidths();
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
setData(data) {
|
|
@@ -8,4 +8,5 @@ import { Candle } from '../../model/candle.model';
|
|
|
8
8
|
export declare const defaultCandleTransformer: VisualCandleCalculator;
|
|
9
9
|
export declare const hollowCandleTransformer: VisualCandleCalculator;
|
|
10
10
|
export declare const trendCandleTransformer: VisualCandleCalculator;
|
|
11
|
+
export declare const lineCandleTransformer: VisualCandleCalculator;
|
|
11
12
|
export declare const getCandleIsActive: (candle: Candle, activeCandle?: Candle) => boolean;
|
|
@@ -14,6 +14,7 @@ export const trendCandleTransformer = (candle, { x, width, activeCandle, prevCan
|
|
|
14
14
|
var _a;
|
|
15
15
|
return new VisualCandle(x, width, candle.open, candle.close, candle.hi, candle.lo, nameDirection((_a = prevCandle === null || prevCandle === void 0 ? void 0 : prevCandle.close) !== null && _a !== void 0 ? _a : candle.close, candle.close), candle, true, getCandleIsActive(candle, activeCandle), candle.close > candle.open);
|
|
16
16
|
};
|
|
17
|
+
export const lineCandleTransformer = trendCandleTransformer;
|
|
17
18
|
export const getCandleIsActive = (candle, activeCandle) => {
|
|
18
19
|
const isActive = activeCandle && activeCandle.idx === candle.idx;
|
|
19
20
|
return isActive !== null && isActive !== void 0 ? isActive : false;
|
|
@@ -13,7 +13,7 @@ type DataPoint<T extends BaseType> = T extends 'candle' ? Candle : DataSeriesPoi
|
|
|
13
13
|
type VisualPoint<T extends BaseType> = T extends 'candle' ? VisualCandle : VisualSeriesPoint;
|
|
14
14
|
export interface PrependedCandlesData {
|
|
15
15
|
prependedCandlesWidth: number;
|
|
16
|
-
|
|
16
|
+
prependedCandles: Candle[];
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* This model is an abstraction which describes manipulations tied to the main data series.
|
|
@@ -40,7 +40,7 @@ export declare class ChartBaseModel<T extends BaseType = 'point'> {
|
|
|
40
40
|
* For given timestamp finds the closest candle in dataset.
|
|
41
41
|
* @param timestamp
|
|
42
42
|
*/
|
|
43
|
-
dataFromTimestamp(timestamp: Timestamp, shouldExtrapolate?: boolean): VisualPoint<T>;
|
|
43
|
+
dataFromTimestamp(timestamp: Timestamp, shouldExtrapolate?: boolean, selectedDataPoints?: DataPoint<T>[]): VisualPoint<T>;
|
|
44
44
|
/**
|
|
45
45
|
* Recalculates the period of the main candle series based on the data points.
|
|
46
46
|
* If a period is detected, it is set as the new period.
|
|
@@ -34,8 +34,8 @@ export class ChartBaseModel {
|
|
|
34
34
|
* @param timestamp
|
|
35
35
|
*/
|
|
36
36
|
// TODO think how to make this function like candleFromX
|
|
37
|
-
dataFromTimestamp(timestamp, shouldExtrapolate = true) {
|
|
38
|
-
const result = searchCandleIndex(timestamp, shouldExtrapolate,
|
|
37
|
+
dataFromTimestamp(timestamp, shouldExtrapolate = true, selectedDataPoints = this.mainDataPoints) {
|
|
38
|
+
const result = searchCandleIndex(timestamp, shouldExtrapolate, selectedDataPoints, this.period);
|
|
39
39
|
return this.dataFromIdx(result.index);
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
@@ -190,6 +190,12 @@ export declare class ChartComponent extends ChartBaseElement {
|
|
|
190
190
|
* @param instrument - name of the instrument to update
|
|
191
191
|
*/
|
|
192
192
|
addLastCandle(candle: Candle, instrumentSymbol?: string): void;
|
|
193
|
+
/**
|
|
194
|
+
* Remove candle by idx and recaculate indexes
|
|
195
|
+
* @param idx - candle index
|
|
196
|
+
* @param instrument - name of the instrument to update
|
|
197
|
+
*/
|
|
198
|
+
removeCandleByIdx(idx: number, instrumentSymbol?: string): void;
|
|
193
199
|
/**
|
|
194
200
|
* Updates last candle value
|
|
195
201
|
* @param candle - updated candle
|
|
@@ -27,7 +27,7 @@ import { HTDataSeriesDrawer } from '../../drawers/ht-data-series.drawer';
|
|
|
27
27
|
import { BaselineModel } from '../../model/baseline.model';
|
|
28
28
|
import { keys } from '../../utils/object.utils';
|
|
29
29
|
import { PriceIncrementsUtils } from '../../utils/price-increments.utils';
|
|
30
|
-
import { defaultCandleTransformer, hollowCandleTransformer, trendCandleTransformer, } from './candle-transformer.functions';
|
|
30
|
+
import { defaultCandleTransformer, hollowCandleTransformer, lineCandleTransformer, trendCandleTransformer, } from './candle-transformer.functions';
|
|
31
31
|
import { deleteCandlesIndex } from './candle.functions';
|
|
32
32
|
import { TrendHistogramDrawer } from '../../drawers/data-series-drawers/trend-histogram.drawer';
|
|
33
33
|
/**
|
|
@@ -87,12 +87,22 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
87
87
|
doActivate() {
|
|
88
88
|
super.doActivate();
|
|
89
89
|
// TODO hack, main data series is created before doActivate, so we need to add it manually
|
|
90
|
-
this.dynamicObjects.model.addObject({
|
|
90
|
+
this.dynamicObjects.model.addObject({
|
|
91
|
+
id: this.chartModel.mainCandleSeries.id,
|
|
92
|
+
paneId: this.chartModel.mainCandleSeries.extentComponent.paneUUID,
|
|
93
|
+
model: this.chartModel.mainCandleSeries,
|
|
94
|
+
drawer: this.dataSeriesDrawer,
|
|
95
|
+
});
|
|
91
96
|
this.addRxSubscription(this.paneManager.dataSeriesAddedSubject.subscribe(series => {
|
|
92
|
-
this.dynamicObjects.model.addObject({
|
|
97
|
+
this.dynamicObjects.model.addObject({
|
|
98
|
+
id: series.id,
|
|
99
|
+
paneId: series.extentComponent.paneUUID,
|
|
100
|
+
model: series,
|
|
101
|
+
drawer: this.dataSeriesDrawer,
|
|
102
|
+
});
|
|
93
103
|
}));
|
|
94
104
|
this.addRxSubscription(this.paneManager.dataSeriesRemovedSubject.subscribe(series => {
|
|
95
|
-
this.dynamicObjects.model.removeObject(series
|
|
105
|
+
this.dynamicObjects.model.removeObject(series.id);
|
|
96
106
|
}));
|
|
97
107
|
}
|
|
98
108
|
/**
|
|
@@ -105,6 +115,7 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
105
115
|
this.registerCandlesTransformer('candle', defaultCandleTransformer);
|
|
106
116
|
this.registerCandlesTransformer('trend', trendCandleTransformer);
|
|
107
117
|
this.registerCandlesTransformer('hollow', hollowCandleTransformer);
|
|
118
|
+
this.registerCandlesTransformer('line', lineCandleTransformer);
|
|
108
119
|
}
|
|
109
120
|
get barTypeValues() {
|
|
110
121
|
// @ts-ignore
|
|
@@ -319,6 +330,14 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
319
330
|
addLastCandle(candle, instrumentSymbol) {
|
|
320
331
|
this.chartModel.addLastCandle(candle, instrumentSymbol);
|
|
321
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Remove candle by idx and recaculate indexes
|
|
335
|
+
* @param idx - candle index
|
|
336
|
+
* @param instrument - name of the instrument to update
|
|
337
|
+
*/
|
|
338
|
+
removeCandleByIdx(idx, instrumentSymbol) {
|
|
339
|
+
this.chartModel.removeCandleByIdx(idx, instrumentSymbol);
|
|
340
|
+
}
|
|
322
341
|
/**
|
|
323
342
|
* Updates last candle value
|
|
324
343
|
* @param candle - updated candle
|
|
@@ -250,7 +250,7 @@ export declare class ChartModel extends ChartBaseElement {
|
|
|
250
250
|
* For given timestamp finds the closest candle in dataset.
|
|
251
251
|
* @param timestamp
|
|
252
252
|
*/
|
|
253
|
-
candleFromTimestamp(timestamp: Timestamp,
|
|
253
|
+
candleFromTimestamp(timestamp: Timestamp, extrapolate?: boolean, selectedCandleSeries?: CandleSeriesModel): VisualCandle;
|
|
254
254
|
/**
|
|
255
255
|
* For given index returns the closest visual candle, or fake candle with correct X coordinate.
|
|
256
256
|
* @param idx - index of candle
|
|
@@ -432,10 +432,16 @@ export declare class ChartModel extends ChartBaseElement {
|
|
|
432
432
|
* @param instrument - name of the instrument to update
|
|
433
433
|
*/
|
|
434
434
|
updateLastCandle(candle: Candle, instrumentSymbol?: string): void;
|
|
435
|
+
/**
|
|
436
|
+
* Remove candle by idx and recaculate indexes
|
|
437
|
+
* @param candle - new candle
|
|
438
|
+
* @param instrument - name of the instrument to update
|
|
439
|
+
*/
|
|
440
|
+
removeCandleByIdx(idx: number, instrumentSymbol?: string): void;
|
|
435
441
|
}
|
|
436
442
|
export interface UpdateCandlesResult {
|
|
437
|
-
prepended:
|
|
438
|
-
appended?:
|
|
443
|
+
prepended: Candle[];
|
|
444
|
+
appended?: Candle[];
|
|
439
445
|
candles: Candle[];
|
|
440
446
|
}
|
|
441
447
|
export type TimeFrameRange = [number, number];
|
|
@@ -24,6 +24,7 @@ import { deleteCandlesIndex, prepareCandle, reindexCandles } from './candle.func
|
|
|
24
24
|
import { ChartInstrument } from './chart.component';
|
|
25
25
|
import { fakeCandle } from './fake-candles';
|
|
26
26
|
import { SecondaryChartColorsPool } from './secondary-chart-colors-pool';
|
|
27
|
+
import { uuid } from '../../utils/uuid.utils';
|
|
27
28
|
export class ChartModel extends ChartBaseElement {
|
|
28
29
|
get mainCandleSeries() {
|
|
29
30
|
return this.candleSeries[0];
|
|
@@ -62,7 +63,7 @@ export class ChartModel extends ChartBaseElement {
|
|
|
62
63
|
};
|
|
63
64
|
this.chartTypeChanged.next(this.config.components.chart.type);
|
|
64
65
|
this.secondaryChartColors = new SecondaryChartColorsPool(this.config);
|
|
65
|
-
const candleSeries = new MainCandleSeriesModel(this.chartBaseModel, this.paneManager.panes[CHART_UUID].mainExtent, this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, new ChartInstrument(), this.candlesTransformersByChartType, this.candleWidthByChartType, Object.assign({}, this.config.colors));
|
|
66
|
+
const candleSeries = new MainCandleSeriesModel(this.chartBaseModel, this.paneManager.panes[CHART_UUID].mainExtent, uuid(), this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, new ChartInstrument(), this.candlesTransformersByChartType, this.candleWidthByChartType, Object.assign({}, this.config.colors));
|
|
66
67
|
candleSeries.config.type = this.config.components.chart.type;
|
|
67
68
|
this.candleSeries.push(candleSeries);
|
|
68
69
|
scale.addXConstraint((_, state) => candleEdgesConstrait(state, this.mainCandleSeries.visualPoints, this.config.components.chart.minCandlesOffset, scale.getBounds()));
|
|
@@ -183,7 +184,7 @@ export class ChartModel extends ChartBaseElement {
|
|
|
183
184
|
// now the visual candles
|
|
184
185
|
candleSeriesModel.recalculateVisualPoints();
|
|
185
186
|
this.candlesSetSubject.next();
|
|
186
|
-
this.
|
|
187
|
+
this.canvasModel.fireDraw();
|
|
187
188
|
}
|
|
188
189
|
return candleSeriesModel;
|
|
189
190
|
}
|
|
@@ -220,7 +221,7 @@ export class ChartModel extends ChartBaseElement {
|
|
|
220
221
|
this.autoScaleOnCandles();
|
|
221
222
|
this.scale.doAutoScale();
|
|
222
223
|
this.candlesSetSubject.next();
|
|
223
|
-
this.
|
|
224
|
+
this.canvasModel.fireDraw();
|
|
224
225
|
}
|
|
225
226
|
/**
|
|
226
227
|
* This function checks if the autoScaleOnCandles state is true. If it is, it calls the doBasicScale() function and then calls the autoScale() function with a true parameter.
|
|
@@ -302,12 +303,12 @@ export class ChartModel extends ChartBaseElement {
|
|
|
302
303
|
});
|
|
303
304
|
// caclulate offset width for prepanded candles
|
|
304
305
|
const prependedCandlesWidth = this.chartBaseModel.mainVisualPoints
|
|
305
|
-
.slice(0, updateResult.prepended)
|
|
306
|
+
.slice(0, updateResult.prepended.length)
|
|
306
307
|
.reduce((acc, cur) => acc + cur.width, 0);
|
|
307
308
|
this.scale.moveXStart(this.scale.xStart + prependedCandlesWidth);
|
|
308
309
|
this.candlesPrependSubject.next({
|
|
309
310
|
prependedCandlesWidth,
|
|
310
|
-
|
|
311
|
+
prependedCandles: updateResult.prepended,
|
|
311
312
|
});
|
|
312
313
|
this.chartBaseModel.recalculatePeriod();
|
|
313
314
|
this.candlesUpdatedSubject.next();
|
|
@@ -346,7 +347,7 @@ export class ChartModel extends ChartBaseElement {
|
|
|
346
347
|
* @returns {CandleSeriesModel} - The newly created CandleSeriesModel object.
|
|
347
348
|
*/
|
|
348
349
|
createCandleSeriesModel(instrument, colors) {
|
|
349
|
-
const candleSeries = new CandleSeriesModel(this.paneManager.panes[CHART_UUID].mainExtent, this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, instrument, this.candlesTransformersByChartType, this.candleWidthByChartType, colors);
|
|
350
|
+
const candleSeries = new CandleSeriesModel(this.paneManager.panes[CHART_UUID].mainExtent, uuid(), this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, instrument, this.candlesTransformersByChartType, this.candleWidthByChartType, colors);
|
|
350
351
|
candleSeries.config.type = 'line';
|
|
351
352
|
this.candleSeries.push(candleSeries);
|
|
352
353
|
return candleSeries;
|
|
@@ -410,7 +411,6 @@ export class ChartModel extends ChartBaseElement {
|
|
|
410
411
|
if (seriesToUpdate) {
|
|
411
412
|
seriesToUpdate.config.type = chartType;
|
|
412
413
|
seriesToUpdate.updateCandleSeriesColors(candleSeriesConfig);
|
|
413
|
-
this.bus.fireDraw([this.canvasModel.canvasId]);
|
|
414
414
|
}
|
|
415
415
|
this.bus.fireDraw([this.canvasModel.canvasId]);
|
|
416
416
|
}
|
|
@@ -549,8 +549,9 @@ export class ChartModel extends ChartBaseElement {
|
|
|
549
549
|
* For given timestamp finds the closest candle in dataset.
|
|
550
550
|
* @param timestamp
|
|
551
551
|
*/
|
|
552
|
-
candleFromTimestamp(timestamp,
|
|
553
|
-
|
|
552
|
+
candleFromTimestamp(timestamp, extrapolate = true, selectedCandleSeries = this.mainCandleSeries) {
|
|
553
|
+
const dataPointsSource = selectedCandleSeries.dataPoints;
|
|
554
|
+
return this.chartBaseModel.dataFromTimestamp(timestamp, extrapolate, dataPointsSource);
|
|
554
555
|
}
|
|
555
556
|
/**
|
|
556
557
|
* For given index returns the closest visual candle, or fake candle with correct X coordinate.
|
|
@@ -798,12 +799,13 @@ export class ChartModel extends ChartBaseElement {
|
|
|
798
799
|
});
|
|
799
800
|
if (lastCandle) {
|
|
800
801
|
series.updateCurrentPrice(lastCandle.close);
|
|
802
|
+
this.paneManager.yExtents.forEach(ext => ext.yAxis.updateOrderedLabels(true));
|
|
801
803
|
}
|
|
802
804
|
if (isInView && lastCandle && candles.length === 1) {
|
|
803
805
|
// can apply some optimization
|
|
804
806
|
// series.recalculateOnlyLastVisualCandle();
|
|
805
807
|
// TODO apply optimization
|
|
806
|
-
this.
|
|
808
|
+
this.canvasModel.fireDraw();
|
|
807
809
|
}
|
|
808
810
|
else {
|
|
809
811
|
series.recalculateVisualPoints();
|
|
@@ -890,7 +892,7 @@ export class ChartModel extends ChartBaseElement {
|
|
|
890
892
|
}
|
|
891
893
|
});
|
|
892
894
|
return {
|
|
893
|
-
prepended: prepend
|
|
895
|
+
prepended: prepend,
|
|
894
896
|
candles: [...prepend, ...targetCopy],
|
|
895
897
|
};
|
|
896
898
|
}
|
|
@@ -910,6 +912,26 @@ export class ChartModel extends ChartBaseElement {
|
|
|
910
912
|
updateLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
|
|
911
913
|
this.updateCandles([candle], instrumentSymbol);
|
|
912
914
|
}
|
|
915
|
+
/**
|
|
916
|
+
* Remove candle by idx and recaculate indexes
|
|
917
|
+
* @param candle - new candle
|
|
918
|
+
* @param instrument - name of the instrument to update
|
|
919
|
+
*/
|
|
920
|
+
removeCandleByIdx(idx, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
|
|
921
|
+
const seriesList = this.findSeriesBySymbol(instrumentSymbol);
|
|
922
|
+
if (seriesList.length === 0) {
|
|
923
|
+
console.warn("removeCandle by id failed. Can't find series", instrumentSymbol);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
seriesList.forEach(series => {
|
|
927
|
+
series.dataPoints = series.dataPoints.slice(0, idx).concat(series.dataPoints.slice(idx + 1));
|
|
928
|
+
reindexCandles(series.dataPoints);
|
|
929
|
+
series.recalculateVisualPoints();
|
|
930
|
+
});
|
|
931
|
+
this.candlesRemovedSubject.next();
|
|
932
|
+
this.candlesUpdatedSubject.next();
|
|
933
|
+
this.canvasModel.fireDraw();
|
|
934
|
+
}
|
|
913
935
|
}
|
|
914
936
|
const sortCandles = (candles) => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1));
|
|
915
937
|
const findFirstNotEmptyCandle = (candles, startIdx, iterateStep) => {
|
|
@@ -952,8 +974,8 @@ const updateCandles = (target, update) => {
|
|
|
952
974
|
}
|
|
953
975
|
});
|
|
954
976
|
return {
|
|
955
|
-
prepended: prepend
|
|
956
|
-
appended: append
|
|
977
|
+
prepended: prepend,
|
|
978
|
+
appended: append,
|
|
957
979
|
candles: [...prepend, ...targetCopy, ...append],
|
|
958
980
|
};
|
|
959
981
|
};
|
|
@@ -23,9 +23,10 @@ export declare class CrossToolComponent extends ChartBaseElement {
|
|
|
23
23
|
private canvasBoundsContainer;
|
|
24
24
|
private drawingManager;
|
|
25
25
|
private paneManager;
|
|
26
|
+
private backgroundCanvasModel;
|
|
26
27
|
readonly model: CrossToolModel;
|
|
27
28
|
private readonly crossToolTypeDrawers;
|
|
28
|
-
constructor(config: FullChartConfig, crossToolCanvasModel: CanvasModel, canvasBoundsContainer: CanvasBoundsContainer, drawingManager: DrawingManager, paneManager: PaneManager, crossEventProducer: CrossEventProducerComponent, hoverProducer: HoverProducerComponent);
|
|
29
|
+
constructor(config: FullChartConfig, crossToolCanvasModel: CanvasModel, canvasBoundsContainer: CanvasBoundsContainer, drawingManager: DrawingManager, paneManager: PaneManager, crossEventProducer: CrossEventProducerComponent, hoverProducer: HoverProducerComponent, backgroundCanvasModel: CanvasModel);
|
|
29
30
|
/**
|
|
30
31
|
* Registers default drawer types for the chart.
|
|
31
32
|
* @private
|
|
@@ -14,13 +14,14 @@ import { NoneDrawerType } from './types/none.drawer';
|
|
|
14
14
|
* Default bundled chart cross tool.
|
|
15
15
|
*/
|
|
16
16
|
export class CrossToolComponent extends ChartBaseElement {
|
|
17
|
-
constructor(config, crossToolCanvasModel, canvasBoundsContainer, drawingManager, paneManager, crossEventProducer, hoverProducer) {
|
|
17
|
+
constructor(config, crossToolCanvasModel, canvasBoundsContainer, drawingManager, paneManager, crossEventProducer, hoverProducer, backgroundCanvasModel) {
|
|
18
18
|
super();
|
|
19
19
|
this.config = config;
|
|
20
20
|
this.crossToolCanvasModel = crossToolCanvasModel;
|
|
21
21
|
this.canvasBoundsContainer = canvasBoundsContainer;
|
|
22
22
|
this.drawingManager = drawingManager;
|
|
23
23
|
this.paneManager = paneManager;
|
|
24
|
+
this.backgroundCanvasModel = backgroundCanvasModel;
|
|
24
25
|
this.crossToolTypeDrawers = {};
|
|
25
26
|
this.model = new CrossToolModel(config.components.crossTool, this.crossToolCanvasModel, crossEventProducer, hoverProducer);
|
|
26
27
|
this.addChildEntity(this.model);
|
|
@@ -41,8 +42,8 @@ export class CrossToolComponent extends ChartBaseElement {
|
|
|
41
42
|
* @returns {void}
|
|
42
43
|
*/
|
|
43
44
|
registerDefaultDrawerTypes() {
|
|
44
|
-
this.registerCrossToolTypeDrawer('cross-and-labels', new CrossAndLabelsDrawerType(this.config, this.canvasBoundsContainer, this.paneManager, () => true));
|
|
45
|
-
this.registerCrossToolTypeDrawer('just-labels', new CrossAndLabelsDrawerType(this.config, this.canvasBoundsContainer, this.paneManager, () => true, true));
|
|
45
|
+
this.registerCrossToolTypeDrawer('cross-and-labels', new CrossAndLabelsDrawerType(this.config, this.canvasBoundsContainer, this.paneManager, this.backgroundCanvasModel, () => true));
|
|
46
|
+
this.registerCrossToolTypeDrawer('just-labels', new CrossAndLabelsDrawerType(this.config, this.canvasBoundsContainer, this.paneManager, this.backgroundCanvasModel, () => true, true));
|
|
46
47
|
this.registerCrossToolTypeDrawer('none', new NoneDrawerType());
|
|
47
48
|
}
|
|
48
49
|
//#region public methods
|