@oanda/labs-crowd-view-widget 1.0.56 → 1.0.58
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/CHANGELOG.md +468 -0
- package/dist/main/CrowdViewWidget/components/Chart/Chart.js +1 -6
- package/dist/main/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getGridConfig.js +5 -4
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getGridConfig.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getGridLines.js +13 -6
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getGridLines.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getLabelsConfig.js +4 -4
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getLabelsConfig.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getTooltipConfig.js +9 -43
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getTooltipConfig.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getXAxisConfig.js +19 -4
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getXAxisConfig.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getYAxisConfig.js +15 -2
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions/getYAxisConfig.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartUtils/formatFullDate.js +27 -0
- package/dist/main/CrowdViewWidget/components/Chart/chartUtils/formatFullDate.js.map +1 -0
- package/dist/main/CrowdViewWidget/components/Chart/chartUtils/getTooltipFormatter.js +14 -23
- package/dist/main/CrowdViewWidget/components/Chart/chartUtils/getTooltipFormatter.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartUtils/index.js +11 -0
- package/dist/main/CrowdViewWidget/components/Chart/chartUtils/index.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer.js +22 -0
- package/dist/main/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer.js.map +1 -0
- package/dist/main/CrowdViewWidget/components/Chart/dataUtils/index.js +8 -8
- package/dist/main/CrowdViewWidget/components/Chart/dataUtils/index.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/getOption.js +4 -4
- package/dist/main/CrowdViewWidget/components/Chart/getOption.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js +11 -7
- package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
- package/dist/main/CrowdViewWidget/constants.js +8 -6
- package/dist/main/CrowdViewWidget/constants.js.map +1 -1
- package/dist/main/translations/sources/en.json +2 -1
- package/dist/module/CrowdViewWidget/components/Chart/Chart.js +2 -7
- package/dist/module/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getGridConfig.js +5 -4
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getGridConfig.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getGridLines.js +13 -6
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getGridLines.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getLabelsConfig.js +4 -4
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getLabelsConfig.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getTooltipConfig.js +9 -42
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getTooltipConfig.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getXAxisConfig.js +20 -5
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getXAxisConfig.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getYAxisConfig.js +15 -2
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions/getYAxisConfig.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartUtils/formatFullDate.js +20 -0
- package/dist/module/CrowdViewWidget/components/Chart/chartUtils/formatFullDate.js.map +1 -0
- package/dist/module/CrowdViewWidget/components/Chart/chartUtils/getTooltipFormatter.js +14 -23
- package/dist/module/CrowdViewWidget/components/Chart/chartUtils/getTooltipFormatter.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartUtils/index.js +1 -0
- package/dist/module/CrowdViewWidget/components/Chart/chartUtils/index.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer.js +15 -0
- package/dist/module/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer.js.map +1 -0
- package/dist/module/CrowdViewWidget/components/Chart/dataUtils/index.js +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/dataUtils/index.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/getOption.js +4 -4
- package/dist/module/CrowdViewWidget/components/Chart/getOption.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js +13 -9
- package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
- package/dist/module/CrowdViewWidget/constants.js +7 -5
- package/dist/module/CrowdViewWidget/constants.js.map +1 -1
- package/dist/module/translations/sources/en.json +2 -1
- package/dist/types/CrowdViewWidget/components/Chart/chartOptions/getTooltipConfig.d.ts +1 -2
- package/dist/types/CrowdViewWidget/components/Chart/chartOptions/getXAxisConfig.d.ts +2 -1
- package/dist/types/CrowdViewWidget/components/Chart/chartOptions/getYAxisConfig.d.ts +4 -2
- package/dist/types/CrowdViewWidget/components/Chart/chartUtils/formatFullDate.d.ts +1 -0
- package/dist/types/CrowdViewWidget/components/Chart/chartUtils/index.d.ts +1 -0
- package/dist/types/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer.d.ts +8 -0
- package/dist/types/CrowdViewWidget/components/Chart/dataUtils/index.d.ts +1 -1
- package/dist/types/CrowdViewWidget/constants.d.ts +5 -3
- package/package.json +3 -3
- package/src/CrowdViewWidget/components/Chart/Chart.tsx +1 -7
- package/src/CrowdViewWidget/components/Chart/chartOptions/getGridConfig.ts +5 -4
- package/src/CrowdViewWidget/components/Chart/chartOptions/getGridLines.ts +19 -10
- package/src/CrowdViewWidget/components/Chart/chartOptions/getLabelsConfig.ts +9 -5
- package/src/CrowdViewWidget/components/Chart/chartOptions/getTooltipConfig.ts +38 -79
- package/src/CrowdViewWidget/components/Chart/chartOptions/getXAxisConfig.ts +26 -2
- package/src/CrowdViewWidget/components/Chart/chartOptions/getYAxisConfig.ts +20 -3
- package/src/CrowdViewWidget/components/Chart/chartUtils/formatFullDate.ts +26 -0
- package/src/CrowdViewWidget/components/Chart/chartUtils/getTooltipFormatter.ts +50 -35
- package/src/CrowdViewWidget/components/Chart/chartUtils/index.ts +1 -0
- package/src/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer.ts +25 -0
- package/src/CrowdViewWidget/components/Chart/dataUtils/index.ts +1 -1
- package/src/CrowdViewWidget/components/Chart/getOption.ts +2 -2
- package/src/CrowdViewWidget/components/Chart/useCrowdViewData.ts +17 -16
- package/src/CrowdViewWidget/constants.ts +11 -7
- package/src/translations/sources/en.json +2 -1
- package/test/components/Chart/dataUtils/getBucketWidthMultiplayer.test.ts +33 -0
- package/dist/main/CrowdViewWidget/components/Chart/dataUtils/getMultiplayerForTimeSpan.js +0 -19
- package/dist/main/CrowdViewWidget/components/Chart/dataUtils/getMultiplayerForTimeSpan.js.map +0 -1
- package/dist/module/CrowdViewWidget/components/Chart/dataUtils/getMultiplayerForTimeSpan.js +0 -12
- package/dist/module/CrowdViewWidget/components/Chart/dataUtils/getMultiplayerForTimeSpan.js.map +0 -1
- package/dist/types/CrowdViewWidget/components/Chart/dataUtils/getMultiplayerForTimeSpan.d.ts +0 -2
- package/src/CrowdViewWidget/components/Chart/dataUtils/getMultiplayerForTimeSpan.ts +0 -13
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { colorPalette } from '@oanda/labs-widget-common';
|
|
2
|
-
import chroma from 'chroma-js';
|
|
3
1
|
import type { TooltipComponentOption } from 'echarts';
|
|
4
2
|
|
|
5
3
|
import type { BookType } from '../../../../gql/types/graphql';
|
|
6
|
-
import { CHART_CONFIG } from '../../../constants';
|
|
7
4
|
import { getTooltipFormatter } from '../chartUtils';
|
|
8
5
|
import type { Bucket, TooltipParam } from '../types';
|
|
9
6
|
|
|
@@ -11,7 +8,6 @@ interface GetTooltipConfigParams {
|
|
|
11
8
|
bookType: BookType;
|
|
12
9
|
bucketWidth: number;
|
|
13
10
|
buckets: Bucket[][];
|
|
14
|
-
displayPrecision: number;
|
|
15
11
|
labelCallback: (key: string, params?: Record<string, unknown>) => string;
|
|
16
12
|
selectedPriceRef: { current: number };
|
|
17
13
|
tooltipLinesColor: string;
|
|
@@ -26,7 +22,6 @@ export const getTooltipConfig = ({
|
|
|
26
22
|
bookType,
|
|
27
23
|
bucketWidth,
|
|
28
24
|
buckets,
|
|
29
|
-
displayPrecision,
|
|
30
25
|
labelCallback,
|
|
31
26
|
selectedPriceRef,
|
|
32
27
|
tooltipLinesColor,
|
|
@@ -35,83 +30,47 @@ export const getTooltipConfig = ({
|
|
|
35
30
|
isDesktop,
|
|
36
31
|
isDark,
|
|
37
32
|
locale,
|
|
38
|
-
}: GetTooltipConfigParams): TooltipComponentOption => {
|
|
39
|
-
|
|
33
|
+
}: GetTooltipConfigParams): TooltipComponentOption => ({
|
|
34
|
+
backgroundColor: 'transparent',
|
|
35
|
+
shadowColor: 'transparent',
|
|
36
|
+
extraCssText: 'width: 100%; z-index: 5;',
|
|
37
|
+
padding: 4,
|
|
38
|
+
textStyle: isDesktop
|
|
40
39
|
? {
|
|
41
|
-
|
|
42
|
-
? chroma(colorPalette.darkGray).alpha(0.95).hex()
|
|
43
|
-
: chroma(colorPalette.darkWhite).alpha(0.95).hex(),
|
|
44
|
-
shadowColor: colorPalette.black10,
|
|
45
|
-
extraCssText: 'z-index: 5;',
|
|
46
|
-
padding: 8,
|
|
47
|
-
alwaysShowContent: false,
|
|
48
|
-
textStyle: {
|
|
49
|
-
fontSize: 11,
|
|
50
|
-
},
|
|
40
|
+
fontSize: 12,
|
|
51
41
|
}
|
|
52
42
|
: {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
extraCssText: 'width: 100%; z-index: 5;',
|
|
56
|
-
padding: 4,
|
|
57
|
-
alwaysShowContent: true,
|
|
58
|
-
textStyle: {
|
|
59
|
-
fontSize: 10,
|
|
60
|
-
lineHeight: 12,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
return {
|
|
64
|
-
...styles,
|
|
65
|
-
trigger: 'axis' as const,
|
|
66
|
-
formatter: (params) =>
|
|
67
|
-
getTooltipFormatter({
|
|
68
|
-
bookType,
|
|
69
|
-
bucketWidth,
|
|
70
|
-
buckets,
|
|
71
|
-
labelCallback,
|
|
72
|
-
params: params as unknown as TooltipParam[],
|
|
73
|
-
selectedPrice: selectedPriceRef.current,
|
|
74
|
-
sentimentLongs,
|
|
75
|
-
sentimentShorts,
|
|
76
|
-
isDesktop,
|
|
77
|
-
locale,
|
|
78
|
-
isDark,
|
|
79
|
-
}),
|
|
80
|
-
hideDelay: 0,
|
|
81
|
-
axisPointer: {
|
|
82
|
-
type: 'cross' as const,
|
|
83
|
-
axis: 'x' as const,
|
|
84
|
-
lineStyle: {
|
|
85
|
-
color: tooltipLinesColor,
|
|
86
|
-
},
|
|
87
|
-
crossStyle: {
|
|
88
|
-
color: tooltipLinesColor,
|
|
89
|
-
},
|
|
90
|
-
label: {
|
|
91
|
-
padding: 0,
|
|
92
|
-
lineHeight: 24,
|
|
93
|
-
formatter: (params: {
|
|
94
|
-
axisDimension?: string;
|
|
95
|
-
axisIndex?: number;
|
|
96
|
-
value: unknown;
|
|
97
|
-
}) => {
|
|
98
|
-
if (params.axisDimension === 'y' && params.axisIndex === 0) {
|
|
99
|
-
selectedPriceRef.current = Number(params.value);
|
|
100
|
-
return ` ${Number(params.value).toFixed(displayPrecision)} `;
|
|
101
|
-
}
|
|
102
|
-
return '';
|
|
103
|
-
},
|
|
43
|
+
fontSize: 10,
|
|
44
|
+
lineHeight: 12,
|
|
104
45
|
},
|
|
46
|
+
alwaysShowContent: true,
|
|
47
|
+
trigger: 'axis' as const,
|
|
48
|
+
formatter: (params) =>
|
|
49
|
+
getTooltipFormatter({
|
|
50
|
+
bookType,
|
|
51
|
+
bucketWidth,
|
|
52
|
+
buckets,
|
|
53
|
+
labelCallback,
|
|
54
|
+
params: params as unknown as TooltipParam[],
|
|
55
|
+
selectedPrice: selectedPriceRef.current,
|
|
56
|
+
sentimentLongs,
|
|
57
|
+
sentimentShorts,
|
|
58
|
+
isDesktop,
|
|
59
|
+
locale,
|
|
60
|
+
isDark,
|
|
61
|
+
}),
|
|
62
|
+
hideDelay: 0,
|
|
63
|
+
axisPointer: {
|
|
64
|
+
type: 'cross' as const,
|
|
65
|
+
axis: 'x' as const,
|
|
66
|
+
lineStyle: {
|
|
67
|
+
color: tooltipLinesColor,
|
|
105
68
|
},
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (isDesktop) {
|
|
109
|
-
return [
|
|
110
|
-
point[0] + CHART_CONFIG.TOOLTIP_OFFSET,
|
|
111
|
-
point[1] + CHART_CONFIG.TOOLTIP_OFFSET,
|
|
112
|
-
];
|
|
113
|
-
}
|
|
114
|
-
return [0, 0];
|
|
69
|
+
crossStyle: {
|
|
70
|
+
color: tooltipLinesColor,
|
|
115
71
|
},
|
|
116
|
-
|
|
117
|
-
}
|
|
72
|
+
z: 30,
|
|
73
|
+
},
|
|
74
|
+
confine: true,
|
|
75
|
+
position: [0, 0],
|
|
76
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { XAXisComponentOption } from 'echarts';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
formatFullDate,
|
|
4
5
|
formatXAxisAdditionalLabel,
|
|
5
6
|
formatXAxisLabel,
|
|
6
7
|
getLabelData,
|
|
@@ -10,12 +11,14 @@ interface GetXAxisConfigParams {
|
|
|
10
11
|
dates: string[];
|
|
11
12
|
isGreaterThanTwoWeeks: boolean;
|
|
12
13
|
locale: string;
|
|
14
|
+
isDesktop: boolean;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export const getXAxisConfig = ({
|
|
16
18
|
dates,
|
|
17
19
|
isGreaterThanTwoWeeks,
|
|
18
20
|
locale,
|
|
21
|
+
isDesktop,
|
|
19
22
|
}: GetXAxisConfigParams): XAXisComponentOption[] => {
|
|
20
23
|
const labelsData = getLabelData({
|
|
21
24
|
dates,
|
|
@@ -38,14 +41,32 @@ export const getXAxisConfig = ({
|
|
|
38
41
|
},
|
|
39
42
|
},
|
|
40
43
|
axisLabel: {
|
|
41
|
-
showMaxLabel: false,
|
|
42
44
|
padding: [8, 16, 8, 16],
|
|
43
45
|
margin: 0,
|
|
44
46
|
formatter: (value: unknown) =>
|
|
45
|
-
|
|
47
|
+
value === dates[dates.length - 1]
|
|
48
|
+
? ''
|
|
49
|
+
: formatXAxisLabel(value, isGreaterThanTwoWeeks, locale),
|
|
46
50
|
},
|
|
47
51
|
boundaryGap: false,
|
|
48
52
|
z: 2,
|
|
53
|
+
axisPointer: {
|
|
54
|
+
label: {
|
|
55
|
+
lineHeight: 22,
|
|
56
|
+
margin: -22,
|
|
57
|
+
padding: [0, 8, 0, 8],
|
|
58
|
+
formatter: (params: {
|
|
59
|
+
axisDimension?: string;
|
|
60
|
+
axisIndex?: number;
|
|
61
|
+
value: unknown;
|
|
62
|
+
}) => {
|
|
63
|
+
const date = new Date(params.value as string);
|
|
64
|
+
|
|
65
|
+
return isDesktop ? formatFullDate(date, locale) : '';
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
z: 100,
|
|
69
|
+
},
|
|
49
70
|
},
|
|
50
71
|
{
|
|
51
72
|
type: 'category',
|
|
@@ -67,6 +88,9 @@ export const getXAxisConfig = ({
|
|
|
67
88
|
formatter: (value: unknown) =>
|
|
68
89
|
formatXAxisAdditionalLabel(value, isGreaterThanTwoWeeks, locale),
|
|
69
90
|
},
|
|
91
|
+
axisPointer: {
|
|
92
|
+
show: false,
|
|
93
|
+
},
|
|
70
94
|
data: dates,
|
|
71
95
|
boundaryGap: false,
|
|
72
96
|
z: 2,
|
|
@@ -5,13 +5,13 @@ import { CHART_CONFIG } from '../../../constants';
|
|
|
5
5
|
interface GetYAxisConfigParams {
|
|
6
6
|
bucketWidth: number;
|
|
7
7
|
displayPrecision: number;
|
|
8
|
-
|
|
8
|
+
selectedPriceRef: { current: number };
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export const getYAxisConfig = ({
|
|
12
12
|
bucketWidth,
|
|
13
13
|
displayPrecision,
|
|
14
|
-
|
|
14
|
+
selectedPriceRef,
|
|
15
15
|
}: GetYAxisConfigParams): YAXisComponentOption[] => [
|
|
16
16
|
{
|
|
17
17
|
type: 'value',
|
|
@@ -35,6 +35,23 @@ export const getYAxisConfig = ({
|
|
|
35
35
|
verticalAlignMaxLabel: 'top',
|
|
36
36
|
formatter: (value: number) => value.toFixed(displayPrecision),
|
|
37
37
|
},
|
|
38
|
+
axisPointer: {
|
|
39
|
+
label: {
|
|
40
|
+
padding: [4, 4, 4, 4],
|
|
41
|
+
margin: -1,
|
|
42
|
+
formatter: (params: {
|
|
43
|
+
axisDimension?: string;
|
|
44
|
+
axisIndex?: number;
|
|
45
|
+
value: unknown;
|
|
46
|
+
}) => {
|
|
47
|
+
if (params.axisDimension === 'y' && params.axisIndex === 0) {
|
|
48
|
+
selectedPriceRef.current = Number(params.value);
|
|
49
|
+
return Number(params.value).toFixed(displayPrecision);
|
|
50
|
+
}
|
|
51
|
+
return '';
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
38
55
|
z: 30,
|
|
39
56
|
},
|
|
40
57
|
{
|
|
@@ -51,7 +68,7 @@ export const getYAxisConfig = ({
|
|
|
51
68
|
margin: 4,
|
|
52
69
|
lineHeight: 20,
|
|
53
70
|
verticalAlignMinLabel: 'bottom',
|
|
54
|
-
verticalAlignMaxLabel:
|
|
71
|
+
verticalAlignMaxLabel: 'top',
|
|
55
72
|
customValues: [
|
|
56
73
|
CHART_CONFIG.SENTIMENT_MIN,
|
|
57
74
|
CHART_CONFIG.SENTIMENT_MAX / 5,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const formatFullDate = (date: Date, locale: string): string => {
|
|
2
|
+
const formattedDate = date
|
|
3
|
+
.toLocaleDateString(locale, {
|
|
4
|
+
day: 'numeric',
|
|
5
|
+
month: '2-digit',
|
|
6
|
+
year: '2-digit',
|
|
7
|
+
})
|
|
8
|
+
.replace(/\//g, '.');
|
|
9
|
+
|
|
10
|
+
const formattedTime = date.toLocaleTimeString(locale, {
|
|
11
|
+
hour: 'numeric',
|
|
12
|
+
minute: '2-digit',
|
|
13
|
+
hour12: false,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
17
|
+
timeZoneName: 'shortOffset',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const parts = formatter.formatToParts(date);
|
|
21
|
+
const timeZoneOffset = parts.find(
|
|
22
|
+
(part) => part.type === 'timeZoneName'
|
|
23
|
+
)?.value;
|
|
24
|
+
|
|
25
|
+
return `${formattedDate} ${formattedTime} ${timeZoneOffset}`;
|
|
26
|
+
};
|
|
@@ -2,18 +2,7 @@ import { colorPalette } from '@oanda/labs-widget-common';
|
|
|
2
2
|
|
|
3
3
|
import { BookType } from '../../../../gql/types/graphql';
|
|
4
4
|
import type { Bucket, TooltipParam } from '../types';
|
|
5
|
-
|
|
6
|
-
const DATE_FORMAT_OPTIONS: Intl.DateTimeFormatOptions = {
|
|
7
|
-
day: 'numeric',
|
|
8
|
-
month: 'numeric',
|
|
9
|
-
year: 'numeric',
|
|
10
|
-
|
|
11
|
-
hour: 'numeric',
|
|
12
|
-
minute: '2-digit',
|
|
13
|
-
hour12: false,
|
|
14
|
-
|
|
15
|
-
timeZoneName: 'shortOffset',
|
|
16
|
-
};
|
|
5
|
+
import { formatFullDate } from './formatFullDate';
|
|
17
6
|
|
|
18
7
|
const SENTIMENT_DISPLAY_PRECISION = 2;
|
|
19
8
|
|
|
@@ -67,7 +56,8 @@ const getSentimentOverbalanceLabel = (
|
|
|
67
56
|
|
|
68
57
|
const formatCandleData = (
|
|
69
58
|
candleData: [number, number, number, number, number],
|
|
70
|
-
labelCallback: (key: string) => string
|
|
59
|
+
labelCallback: (key: string) => string,
|
|
60
|
+
isDesktop: boolean
|
|
71
61
|
): string => {
|
|
72
62
|
const [, open, close, low, high] = candleData;
|
|
73
63
|
const candleLabel = labelCallback('candle');
|
|
@@ -76,11 +66,19 @@ const formatCandleData = (
|
|
|
76
66
|
const lowLabel = labelCallback('low');
|
|
77
67
|
const highLabel = labelCallback('high');
|
|
78
68
|
|
|
79
|
-
return
|
|
69
|
+
return isDesktop
|
|
70
|
+
? `<div><b>${candleLabel}:</b></div>
|
|
71
|
+
<div style="display: flex; gap: 4px; margin-right: 4px;">
|
|
80
72
|
<div>${openLabel}: ${open} </div>
|
|
81
|
-
<div>${
|
|
73
|
+
<div>${highLabel}: ${high} </div>
|
|
82
74
|
<div>${lowLabel}: ${low} </div>
|
|
75
|
+
<div>${closeLabel}: ${close} </div>
|
|
76
|
+
</div>`
|
|
77
|
+
: `<div><b>${candleLabel}:</b></div>
|
|
78
|
+
<div>${openLabel}: ${open} </div>
|
|
83
79
|
<div>${highLabel}: ${high} </div>
|
|
80
|
+
<div>${lowLabel}: ${low} </div>
|
|
81
|
+
<div>${closeLabel}: ${close} </div>
|
|
84
82
|
`;
|
|
85
83
|
};
|
|
86
84
|
|
|
@@ -112,8 +110,8 @@ const formatBookData = ({
|
|
|
112
110
|
|
|
113
111
|
return isDesktop
|
|
114
112
|
? `<div><b>${labelCallback(bookLabelKey)}:</b></div>
|
|
115
|
-
<
|
|
116
|
-
<
|
|
113
|
+
<span style="margin-right: 4px;">${labelCallback('price_range')}: ${priceRangeStart} - ${priceRangeEnd} </span>
|
|
114
|
+
<span style="margin-right: 4px;">${labelCallback(sentimentLabel)}: ${sentimentValue}% </span>`
|
|
117
115
|
: `<div><b>${labelCallback(bookLabelKey)}:</b></div>
|
|
118
116
|
<div>${labelCallback('price_range')}:</div>
|
|
119
117
|
<div>${priceRangeStart} - ${priceRangeEnd} </div>
|
|
@@ -124,9 +122,14 @@ const formatBookData = ({
|
|
|
124
122
|
const formatSentimentData = (
|
|
125
123
|
sentimentLong: number,
|
|
126
124
|
sentimentShort: number,
|
|
127
|
-
labelCallback: (key: string) => string
|
|
125
|
+
labelCallback: (key: string) => string,
|
|
126
|
+
isDesktop: boolean
|
|
128
127
|
): string => {
|
|
129
|
-
return
|
|
128
|
+
return isDesktop
|
|
129
|
+
? `<div><b>${labelCallback('sentiment')}:</b></div>
|
|
130
|
+
<span style="margin-right: 4px;">${labelCallback('long')}: ${sentimentLong.toFixed(SENTIMENT_DISPLAY_PRECISION)}% </span>
|
|
131
|
+
<span style="margin-right: 4px;">${labelCallback('short')}: ${sentimentShort.toFixed(SENTIMENT_DISPLAY_PRECISION)}% </span>`
|
|
132
|
+
: `<div><b>${labelCallback('sentiment')}:</b></div>
|
|
130
133
|
<div>${labelCallback('long')}: ${sentimentLong.toFixed(SENTIMENT_DISPLAY_PRECISION)}% </div>
|
|
131
134
|
<div>${labelCallback('short')}: ${sentimentShort.toFixed(SENTIMENT_DISPLAY_PRECISION)}% </div>`;
|
|
132
135
|
};
|
|
@@ -214,11 +217,9 @@ export const getTooltipFormatter = ({
|
|
|
214
217
|
return '';
|
|
215
218
|
}
|
|
216
219
|
|
|
217
|
-
const timeFormatted = time
|
|
218
|
-
.toLocaleString(locale, DATE_FORMAT_OPTIONS)
|
|
219
|
-
.replace(/\//g, '.');
|
|
220
|
+
const timeFormatted = formatFullDate(time, locale);
|
|
220
221
|
const candleSection = showCandles
|
|
221
|
-
? formatCandleData(candleData, labelCallback)
|
|
222
|
+
? formatCandleData(candleData, labelCallback, isDesktop)
|
|
222
223
|
: '';
|
|
223
224
|
|
|
224
225
|
const bookSection = matchedBucket
|
|
@@ -234,7 +235,12 @@ export const getTooltipFormatter = ({
|
|
|
234
235
|
|
|
235
236
|
const sentimentSection =
|
|
236
237
|
showSentiment && sentimentLong && sentimentShort
|
|
237
|
-
? formatSentimentData(
|
|
238
|
+
? formatSentimentData(
|
|
239
|
+
sentimentLong,
|
|
240
|
+
sentimentShort,
|
|
241
|
+
labelCallback,
|
|
242
|
+
isDesktop
|
|
243
|
+
)
|
|
238
244
|
: '';
|
|
239
245
|
|
|
240
246
|
if (isDesktop) {
|
|
@@ -243,7 +249,7 @@ export const getTooltipFormatter = ({
|
|
|
243
249
|
candleSection,
|
|
244
250
|
sentimentSection,
|
|
245
251
|
bookSection,
|
|
246
|
-
|
|
252
|
+
isDark,
|
|
247
253
|
});
|
|
248
254
|
}
|
|
249
255
|
|
|
@@ -264,20 +270,29 @@ interface TooltipSections {
|
|
|
264
270
|
}
|
|
265
271
|
|
|
266
272
|
const buildDesktopTooltip = ({
|
|
267
|
-
timeFormatted,
|
|
268
273
|
candleSection,
|
|
269
274
|
sentimentSection,
|
|
270
275
|
bookSection,
|
|
271
|
-
|
|
272
|
-
}: TooltipSections & {
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
isDark,
|
|
277
|
+
}: TooltipSections & {
|
|
278
|
+
isDark: boolean;
|
|
279
|
+
}): string => {
|
|
280
|
+
const backgroundColor = isDark ? colorPalette.black : colorPalette.white;
|
|
281
|
+
const fullWidth = TOOLTIP_STYLES.FULL_WIDTH;
|
|
275
282
|
|
|
276
|
-
return `<div style="
|
|
277
|
-
<div style="
|
|
278
|
-
<div style="
|
|
279
|
-
|
|
280
|
-
|
|
283
|
+
return `<div style="width: ${fullWidth}; background-color: ${backgroundColor};">
|
|
284
|
+
<div style="width: ${fullWidth}; display: flex; justify-content: space-between;">
|
|
285
|
+
<div style="width: 40%;">
|
|
286
|
+
${candleSection}
|
|
287
|
+
</div>
|
|
288
|
+
<div style="width: 22%;">
|
|
289
|
+
${sentimentSection}
|
|
290
|
+
</div>
|
|
291
|
+
<div style="width: 38%;">
|
|
292
|
+
${bookSection}
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
</div>`;
|
|
281
296
|
};
|
|
282
297
|
|
|
283
298
|
const buildMobileTooltip = ({
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DISPLAYED_BUCKETS_COUNT,
|
|
3
|
+
INSTRUMENTS_CONFIG,
|
|
4
|
+
} from '../../../constants';
|
|
5
|
+
import type { InstrumentId } from '../../../types';
|
|
6
|
+
|
|
7
|
+
interface GetBucketWidthMultiplayerParams {
|
|
8
|
+
minPrice: number;
|
|
9
|
+
maxPrice: number;
|
|
10
|
+
instrument: InstrumentId;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const getBucketWidthMultiplayer = ({
|
|
14
|
+
minPrice,
|
|
15
|
+
maxPrice,
|
|
16
|
+
instrument,
|
|
17
|
+
}: GetBucketWidthMultiplayerParams): number => {
|
|
18
|
+
const { defaultBucketWidth } = INSTRUMENTS_CONFIG[instrument];
|
|
19
|
+
const priceRange = maxPrice - minPrice;
|
|
20
|
+
|
|
21
|
+
const calculatedMultiplier =
|
|
22
|
+
priceRange / (defaultBucketWidth * DISPLAYED_BUCKETS_COUNT);
|
|
23
|
+
|
|
24
|
+
return Math.max(1, Math.ceil(calculatedMultiplier));
|
|
25
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export * from './getBucketWidthMultiplayer';
|
|
1
2
|
export * from './getInstrumentConfigForDivision';
|
|
2
|
-
export * from './getMultiplayerForTimeSpan';
|
|
3
3
|
export * from './getTimeSpanForGranularity';
|
|
4
4
|
export * from './processOrderPositionBooks';
|
|
5
5
|
export * from './processPriceCandles';
|
|
@@ -89,7 +89,6 @@ export const getOption: GetOptionType = ({
|
|
|
89
89
|
bookType,
|
|
90
90
|
bucketWidth,
|
|
91
91
|
buckets,
|
|
92
|
-
displayPrecision,
|
|
93
92
|
labelCallback,
|
|
94
93
|
selectedPriceRef,
|
|
95
94
|
tooltipLinesColor: styles.tooltipLinesColor,
|
|
@@ -104,11 +103,12 @@ export const getOption: GetOptionType = ({
|
|
|
104
103
|
dates,
|
|
105
104
|
isGreaterThanTwoWeeks,
|
|
106
105
|
locale,
|
|
106
|
+
isDesktop,
|
|
107
107
|
}),
|
|
108
108
|
yAxis: getYAxisConfig({
|
|
109
|
-
isDesktop,
|
|
110
109
|
bucketWidth,
|
|
111
110
|
displayPrecision,
|
|
111
|
+
selectedPriceRef,
|
|
112
112
|
}),
|
|
113
113
|
dataZoom: getDataZoomConfig({ isDesktop }),
|
|
114
114
|
visualMap: getVisualMapConfig({
|
|
@@ -12,10 +12,10 @@ import type {
|
|
|
12
12
|
GetSentimentsQuery,
|
|
13
13
|
GetSentimentsQueryVariables,
|
|
14
14
|
} from '../../../gql/types/graphql';
|
|
15
|
-
import {
|
|
15
|
+
import { DataSource } from '../../../gql/types/graphql';
|
|
16
16
|
import { BUCKET_CONFIG, INSTRUMENTS_CONFIG } from '../../constants';
|
|
17
17
|
import {
|
|
18
|
-
|
|
18
|
+
getBucketWidthMultiplayer,
|
|
19
19
|
getTimeSpanForGranularity,
|
|
20
20
|
processOrderPositionBooks,
|
|
21
21
|
processPriceCandles,
|
|
@@ -30,11 +30,6 @@ export const useCrowdViewData = ({
|
|
|
30
30
|
division,
|
|
31
31
|
granularity,
|
|
32
32
|
}: UseCrowdViewDataProps): UseCrowdViewDataReturn => {
|
|
33
|
-
const dataSource =
|
|
34
|
-
division === Division.Ogm || division === Division.Oj
|
|
35
|
-
? DataSource.Mt5
|
|
36
|
-
: DataSource.V20;
|
|
37
|
-
|
|
38
33
|
// Get price candles data
|
|
39
34
|
const {
|
|
40
35
|
loading: priceCandlesLoading,
|
|
@@ -44,12 +39,9 @@ export const useCrowdViewData = ({
|
|
|
44
39
|
getPriceCandles,
|
|
45
40
|
{
|
|
46
41
|
variables: {
|
|
47
|
-
dataSource,
|
|
42
|
+
dataSource: DataSource.V20,
|
|
48
43
|
division,
|
|
49
|
-
instrument:
|
|
50
|
-
dataSource === DataSource.Mt5
|
|
51
|
-
? INSTRUMENTS_CONFIG[instrument].mt5name
|
|
52
|
-
: INSTRUMENTS_CONFIG[instrument].v20name,
|
|
44
|
+
instrument: INSTRUMENTS_CONFIG[instrument].v20name,
|
|
53
45
|
granularity,
|
|
54
46
|
timeSpan: getTimeSpanForGranularity(granularity),
|
|
55
47
|
},
|
|
@@ -69,6 +61,15 @@ export const useCrowdViewData = ({
|
|
|
69
61
|
pipsLocation,
|
|
70
62
|
} = useMemo(() => processPriceCandles(priceCandlesData), [priceCandlesData]);
|
|
71
63
|
|
|
64
|
+
const bucketWidthMultiplayer = useMemo(
|
|
65
|
+
() =>
|
|
66
|
+
getBucketWidthMultiplayer({
|
|
67
|
+
minPrice,
|
|
68
|
+
maxPrice,
|
|
69
|
+
instrument,
|
|
70
|
+
}),
|
|
71
|
+
[minPrice, maxPrice, instrument]
|
|
72
|
+
);
|
|
72
73
|
// Get order position books data
|
|
73
74
|
const {
|
|
74
75
|
loading: orderPositionLoading,
|
|
@@ -79,12 +80,12 @@ export const useCrowdViewData = ({
|
|
|
79
80
|
{
|
|
80
81
|
variables: {
|
|
81
82
|
instrument: INSTRUMENTS_CONFIG[instrument].v20name,
|
|
82
|
-
bookType
|
|
83
|
+
bookType,
|
|
83
84
|
timeSpan: getTimeSpanForGranularity(granularity),
|
|
84
85
|
granularity,
|
|
85
86
|
maxBookPrice: maxPrice,
|
|
86
87
|
minBookPrice: minPrice,
|
|
87
|
-
bucketMultiplier:
|
|
88
|
+
bucketMultiplier: bucketWidthMultiplayer,
|
|
88
89
|
bucketMargin: BUCKET_CONFIG.PRICE_MARGIN_MULTIPLIER,
|
|
89
90
|
},
|
|
90
91
|
fetchPolicy: 'no-cache',
|
|
@@ -182,7 +183,7 @@ export const useCrowdViewData = ({
|
|
|
182
183
|
bucketWidth:
|
|
183
184
|
bucketWidth ||
|
|
184
185
|
INSTRUMENTS_CONFIG[instrument].defaultBucketWidth *
|
|
185
|
-
|
|
186
|
+
bucketWidthMultiplayer,
|
|
186
187
|
buckets,
|
|
187
188
|
displayPrecision: pipsLocation,
|
|
188
189
|
bookType,
|
|
@@ -203,8 +204,8 @@ export const useCrowdViewData = ({
|
|
|
203
204
|
sentimentShorts,
|
|
204
205
|
sentimentLongs,
|
|
205
206
|
bucketWidth,
|
|
206
|
-
granularity,
|
|
207
207
|
instrument,
|
|
208
|
+
bucketWidthMultiplayer,
|
|
208
209
|
buckets,
|
|
209
210
|
pipsLocation,
|
|
210
211
|
bookType,
|
|
@@ -15,6 +15,8 @@ export const TIME_THRESHOLDS = {
|
|
|
15
15
|
TWO_WEEKS_MS: 14 * 24 * 60 * 60 * 1000,
|
|
16
16
|
} as const;
|
|
17
17
|
|
|
18
|
+
export const DISPLAYED_BUCKETS_COUNT = 40;
|
|
19
|
+
|
|
18
20
|
const CHART_CONFIG_STATIC = {
|
|
19
21
|
MAIN_HEIGHT_DESKTOP: 410,
|
|
20
22
|
MAIN_HEIGHT_MOBILE: 330,
|
|
@@ -32,22 +34,24 @@ const CHART_CONFIG_STATIC = {
|
|
|
32
34
|
X_AXIS_DATE_PADDING: ' ',
|
|
33
35
|
SENTIMENT_MIN: 0,
|
|
34
36
|
SENTIMENT_MAX: 100,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
TOP_LABEL_SPACE_DESKTOP: 0,
|
|
38
|
+
TOP_LABEL_SPACE_MOBILE: 24,
|
|
39
|
+
TOOLTIP_HEIGHT_MOBILE: 85,
|
|
40
|
+
TOOLTIP_HEIGHT_DESKTOP: 46,
|
|
38
41
|
TOOLTIP_OFFSET: 8,
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
const CHART_CONFIG_CALCULATED = {
|
|
42
45
|
HEIGHT_DESKTOP:
|
|
43
46
|
CHART_CONFIG_STATIC.MAIN_HEIGHT_DESKTOP +
|
|
44
|
-
CHART_CONFIG_STATIC.
|
|
45
|
-
CHART_CONFIG_STATIC.X_LABEL_SIZE
|
|
47
|
+
CHART_CONFIG_STATIC.TOP_LABEL_SPACE_DESKTOP +
|
|
48
|
+
CHART_CONFIG_STATIC.X_LABEL_SIZE +
|
|
49
|
+
CHART_CONFIG_STATIC.TOOLTIP_HEIGHT_DESKTOP,
|
|
46
50
|
HEIGHT_MOBILE:
|
|
47
51
|
CHART_CONFIG_STATIC.MAIN_HEIGHT_MOBILE +
|
|
48
52
|
CHART_CONFIG_STATIC.X_LABEL_SIZE +
|
|
49
|
-
CHART_CONFIG_STATIC.
|
|
50
|
-
CHART_CONFIG_STATIC.
|
|
53
|
+
CHART_CONFIG_STATIC.TOP_LABEL_SPACE_MOBILE +
|
|
54
|
+
CHART_CONFIG_STATIC.TOOLTIP_HEIGHT_MOBILE,
|
|
51
55
|
};
|
|
52
56
|
export const CHART_CONFIG = {
|
|
53
57
|
...CHART_CONFIG_STATIC,
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"sentiment": "Sentiment",
|
|
30
30
|
"short": "Short",
|
|
31
31
|
"short_overbalance": "Short overbalance",
|
|
32
|
-
"tap_chart_to_see_more_details": "Tap chart to see more details",
|
|
32
|
+
"tap_chart_to_see_more_details": "Tap the chart to see more details",
|
|
33
|
+
"hover_chart_to_see_more_details": "Hover over the chart to see more details",
|
|
33
34
|
"trades": "Trades"
|
|
34
35
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getBucketWidthMultiplayer } from '../../../../src/CrowdViewWidget/components/Chart/dataUtils/getBucketWidthMultiplayer';
|
|
2
|
+
import { InstrumentId } from '../../../../src/CrowdViewWidget/types';
|
|
3
|
+
|
|
4
|
+
describe('getBucketWidthMultiplayer', () => {
|
|
5
|
+
describe('happy path', () => {
|
|
6
|
+
it('should calculate multiplier correctly for EUR_USD with standard price range', () => {
|
|
7
|
+
const result = getBucketWidthMultiplayer({
|
|
8
|
+
minPrice: 1.05,
|
|
9
|
+
maxPrice: 1.1,
|
|
10
|
+
instrument: InstrumentId.EUR_USD,
|
|
11
|
+
});
|
|
12
|
+
expect(result).toBe(3);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should calculate multiplier correctly for EUR_JPY with standard price range', () => {
|
|
16
|
+
const result = getBucketWidthMultiplayer({
|
|
17
|
+
minPrice: 140.0,
|
|
18
|
+
maxPrice: 150.0,
|
|
19
|
+
instrument: InstrumentId.EUR_JPY,
|
|
20
|
+
});
|
|
21
|
+
expect(result).toBe(5);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return 1 when calculated multiplier is less than 1', () => {
|
|
26
|
+
const result = getBucketWidthMultiplayer({
|
|
27
|
+
minPrice: 1.0,
|
|
28
|
+
maxPrice: 1.01,
|
|
29
|
+
instrument: InstrumentId.EUR_USD,
|
|
30
|
+
});
|
|
31
|
+
expect(result).toBe(1);
|
|
32
|
+
});
|
|
33
|
+
});
|