@gravity-ui/chartkit 5.4.0 → 5.6.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/build/constants/widget-data.d.ts +1 -0
- package/build/constants/widget-data.js +1 -0
- package/build/i18n/keysets/en.json +2 -1
- package/build/i18n/keysets/ru.json +2 -4
- package/build/plugins/d3/examples/area/TwoYAxis.d.ts +2 -0
- package/build/plugins/d3/examples/area/TwoYAxis.js +58 -0
- package/build/plugins/d3/examples/bar-x/TwoYAxis.d.ts +2 -0
- package/build/plugins/d3/examples/bar-x/TwoYAxis.js +58 -0
- package/build/plugins/d3/examples/line/TwoYAxis.d.ts +2 -0
- package/build/plugins/d3/examples/line/TwoYAxis.js +58 -0
- package/build/plugins/d3/examples/mars-weather.d.ts +13 -0
- package/build/plugins/d3/examples/mars-weather.js +1203 -0
- package/build/plugins/d3/examples/scatter/TwoYAxis.d.ts +2 -0
- package/build/plugins/d3/examples/scatter/TwoYAxis.js +58 -0
- package/build/plugins/d3/renderer/components/AxisY.d.ts +1 -1
- package/build/plugins/d3/renderer/components/AxisY.js +112 -79
- package/build/plugins/d3/renderer/components/Chart.js +4 -3
- package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.js +19 -2
- package/build/plugins/d3/renderer/constants/defaults/series-options.d.ts +7 -1
- package/build/plugins/d3/renderer/constants/defaults/series-options.js +14 -0
- package/build/plugins/d3/renderer/hooks/useAxisScales/index.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useAxisScales/index.js +8 -1
- package/build/plugins/d3/renderer/hooks/useChartDimensions/utils.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useChartDimensions/utils.js +11 -10
- package/build/plugins/d3/renderer/hooks/useChartOptions/types.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useChartOptions/x-axis.js +1 -0
- package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +69 -53
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-legend.js +3 -3
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-scatter.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-waterfall.d.ts +10 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-waterfall.js +36 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepareSeries.js +8 -0
- package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +18 -2
- package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.js +7 -6
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.js +4 -4
- package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.js +1 -1
- package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +3 -2
- package/build/plugins/d3/renderer/hooks/useShapes/index.js +19 -1
- package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.d.ts +1 -1
- package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.d.ts +2 -2
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/styles.css +4 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.d.ts +12 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.js +125 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.d.ts +12 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.js +132 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/types.d.ts +14 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/types.js +1 -0
- package/build/plugins/d3/renderer/utils/get-closest-data.js +16 -5
- package/build/plugins/d3/renderer/utils/index.d.ts +1 -0
- package/build/plugins/d3/renderer/utils/index.js +11 -0
- package/build/plugins/d3/renderer/utils/series/index.d.ts +1 -0
- package/build/plugins/d3/renderer/utils/series/index.js +1 -0
- package/build/plugins/d3/renderer/utils/series/waterfall.d.ts +4 -0
- package/build/plugins/d3/renderer/utils/series/waterfall.js +25 -0
- package/build/plugins/d3/renderer/utils/text.js +1 -1
- package/build/plugins/d3/renderer/validation/index.js +13 -4
- package/build/plugins/d3/utils/pie-center-text.js +1 -1
- package/build/plugins/highcharts/renderer/components/HighchartsComponent.d.ts +5 -0
- package/build/plugins/highcharts/renderer/helpers/config/config.d.ts +5 -0
- package/build/plugins/highcharts/renderer/helpers/config/config.js +8 -0
- package/build/plugins/highcharts/renderer/helpers/config/options.js +1 -1
- package/build/plugins/highcharts/renderer/helpers/graph.d.ts +5 -0
- package/build/types/widget-data/area.d.ts +2 -0
- package/build/types/widget-data/bar-x.d.ts +2 -0
- package/build/types/widget-data/index.d.ts +1 -0
- package/build/types/widget-data/index.js +1 -0
- package/build/types/widget-data/line.d.ts +2 -0
- package/build/types/widget-data/scatter.d.ts +2 -0
- package/build/types/widget-data/series.d.ts +21 -2
- package/build/types/widget-data/tooltip.d.ts +6 -1
- package/build/types/widget-data/waterfall.d.ts +39 -0
- package/build/types/widget-data/waterfall.js +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { dateTime } from '@gravity-ui/date-utils';
|
|
3
|
+
import { ChartKit } from '../../../../components/ChartKit';
|
|
4
|
+
import { ExampleWrapper } from '../ExampleWrapper';
|
|
5
|
+
import marsWeatherData from '../mars-weather';
|
|
6
|
+
export const TwoYAxis = () => {
|
|
7
|
+
const data = marsWeatherData;
|
|
8
|
+
const minTempData = data.map((d) => ({
|
|
9
|
+
x: dateTime({ input: d.terrestrial_date, format: 'YYYY-MM-DD' }).valueOf(),
|
|
10
|
+
y: d.min_temp,
|
|
11
|
+
}));
|
|
12
|
+
const maxTempData = data.map((d) => ({
|
|
13
|
+
x: dateTime({ input: d.terrestrial_date, format: 'YYYY-MM-DD' }).valueOf(),
|
|
14
|
+
y: d.max_temp,
|
|
15
|
+
}));
|
|
16
|
+
const widgetData = {
|
|
17
|
+
series: {
|
|
18
|
+
data: [
|
|
19
|
+
{
|
|
20
|
+
type: 'scatter',
|
|
21
|
+
data: minTempData,
|
|
22
|
+
name: 'Min Temperature',
|
|
23
|
+
yAxis: 0,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: 'scatter',
|
|
27
|
+
data: maxTempData,
|
|
28
|
+
name: 'Max Temperature',
|
|
29
|
+
yAxis: 1,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
yAxis: [
|
|
34
|
+
{
|
|
35
|
+
title: {
|
|
36
|
+
text: 'Min',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: {
|
|
41
|
+
text: 'Max',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
xAxis: {
|
|
46
|
+
type: 'datetime',
|
|
47
|
+
title: {
|
|
48
|
+
text: 'Terrestrial date',
|
|
49
|
+
},
|
|
50
|
+
ticks: { pixelInterval: 200 },
|
|
51
|
+
},
|
|
52
|
+
title: {
|
|
53
|
+
text: 'Mars weather',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
return (React.createElement(ExampleWrapper, null,
|
|
57
|
+
React.createElement(ChartKit, { type: "d3", data: widgetData })));
|
|
58
|
+
};
|
|
@@ -2,9 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import type { ChartScale, PreparedAxis } from '../hooks';
|
|
3
3
|
type Props = {
|
|
4
4
|
axises: PreparedAxis[];
|
|
5
|
+
scale: ChartScale[];
|
|
5
6
|
width: number;
|
|
6
7
|
height: number;
|
|
7
|
-
scale: ChartScale;
|
|
8
8
|
};
|
|
9
9
|
export declare const AxisY: ({ axises, width, height, scale }: Props) => React.JSX.Element;
|
|
10
10
|
export {};
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { axisLeft, select } from 'd3';
|
|
2
|
+
import { axisLeft, axisRight, line, select } from 'd3';
|
|
3
3
|
import { block } from '../../../../utils/cn';
|
|
4
4
|
import { calculateCos, calculateSin, formatAxisTickLabel, getClosestPointsRange, getScaleTicks, getTicksCount, parseTransformStyle, setEllipsisForOverflowText, setEllipsisForOverflowTexts, } from '../utils';
|
|
5
5
|
const b = block('d3-axis');
|
|
6
|
-
function transformLabel(
|
|
6
|
+
function transformLabel(args) {
|
|
7
|
+
const { node, axis } = args;
|
|
7
8
|
let topOffset = axis.labels.lineHeight / 2;
|
|
8
|
-
let leftOffset =
|
|
9
|
+
let leftOffset = axis.labels.margin;
|
|
10
|
+
if (axis.position === 'left') {
|
|
11
|
+
leftOffset = leftOffset * -1;
|
|
12
|
+
}
|
|
9
13
|
if (axis.labels.rotation) {
|
|
10
14
|
if (axis.labels.rotation > 0) {
|
|
11
15
|
leftOffset -= axis.labels.lineHeight * calculateSin(axis.labels.rotation);
|
|
@@ -24,92 +28,121 @@ function transformLabel(node, axis) {
|
|
|
24
28
|
}
|
|
25
29
|
return `translate(${leftOffset}px, ${topOffset}px)`;
|
|
26
30
|
}
|
|
31
|
+
function getAxisGenerator(args) {
|
|
32
|
+
const { preparedAxis, axisGenerator: generator, width, height, scale } = args;
|
|
33
|
+
const tickSize = preparedAxis.grid.enabled ? width * -1 : 0;
|
|
34
|
+
const step = getClosestPointsRange(preparedAxis, getScaleTicks(scale));
|
|
35
|
+
let axisGenerator = generator
|
|
36
|
+
.tickSize(tickSize)
|
|
37
|
+
.tickPadding(preparedAxis.labels.margin)
|
|
38
|
+
.tickFormat((value) => {
|
|
39
|
+
if (!preparedAxis.labels.enabled) {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
return formatAxisTickLabel({
|
|
43
|
+
axis: preparedAxis,
|
|
44
|
+
value,
|
|
45
|
+
step,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
const ticksCount = getTicksCount({ axis: preparedAxis, range: height });
|
|
49
|
+
if (ticksCount) {
|
|
50
|
+
axisGenerator = axisGenerator.ticks(ticksCount);
|
|
51
|
+
}
|
|
52
|
+
return axisGenerator;
|
|
53
|
+
}
|
|
27
54
|
export const AxisY = ({ axises, width, height, scale }) => {
|
|
28
55
|
const ref = React.useRef(null);
|
|
29
56
|
React.useEffect(() => {
|
|
30
57
|
if (!ref.current) {
|
|
31
58
|
return;
|
|
32
59
|
}
|
|
33
|
-
const axis = axises[0];
|
|
34
60
|
const svgElement = select(ref.current);
|
|
35
61
|
svgElement.selectAll('*').remove();
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.
|
|
40
|
-
.
|
|
41
|
-
.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
62
|
+
const axisSelection = svgElement
|
|
63
|
+
.selectAll('axis')
|
|
64
|
+
.data(axises)
|
|
65
|
+
.join('g')
|
|
66
|
+
.attr('class', b())
|
|
67
|
+
.style('transform', (_d, index) => (index === 0 ? '' : `translate(${width}px, 0)`));
|
|
68
|
+
axisSelection.each((d, index, node) => {
|
|
69
|
+
const seriesScale = scale[index];
|
|
70
|
+
const axisItem = select(node[index]);
|
|
71
|
+
const yAxisGenerator = getAxisGenerator({
|
|
72
|
+
axisGenerator: index === 0
|
|
73
|
+
? axisLeft(seriesScale)
|
|
74
|
+
: axisRight(seriesScale),
|
|
75
|
+
preparedAxis: d,
|
|
76
|
+
height,
|
|
77
|
+
width,
|
|
78
|
+
scale: seriesScale,
|
|
49
79
|
});
|
|
80
|
+
yAxisGenerator(axisItem);
|
|
81
|
+
if (d.labels.enabled) {
|
|
82
|
+
const tickTexts = axisItem
|
|
83
|
+
.selectAll('.tick text')
|
|
84
|
+
// The offset must be applied before the labels are rotated.
|
|
85
|
+
// Therefore, we reset the values and make an offset in transform attribute.
|
|
86
|
+
// FIXME: give up axisLeft(d3) and switch to our own generation method
|
|
87
|
+
.attr('x', null)
|
|
88
|
+
.attr('dy', null)
|
|
89
|
+
.style('font-size', d.labels.style.fontSize)
|
|
90
|
+
.style('transform', function () {
|
|
91
|
+
return transformLabel({ node: this, axis: d });
|
|
92
|
+
});
|
|
93
|
+
const textMaxWidth = !d.labels.rotation || Math.abs(d.labels.rotation) % 360 !== 90
|
|
94
|
+
? d.labels.maxWidth
|
|
95
|
+
: (height - d.labels.padding * (tickTexts.size() - 1)) / tickTexts.size();
|
|
96
|
+
tickTexts.call(setEllipsisForOverflowTexts, textMaxWidth);
|
|
97
|
+
}
|
|
98
|
+
// remove overlapping ticks
|
|
99
|
+
// Note: this method do not prepared for rotated labels
|
|
100
|
+
if (!d.labels.rotation) {
|
|
101
|
+
let elementY = 0;
|
|
102
|
+
axisItem
|
|
103
|
+
.selectAll('.tick')
|
|
104
|
+
.filter(function (_d, tickIndex) {
|
|
105
|
+
const tickNode = this;
|
|
106
|
+
const r = tickNode.getBoundingClientRect();
|
|
107
|
+
if (r.bottom > elementY && tickIndex !== 0) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
elementY = r.top - d.labels.padding;
|
|
111
|
+
return false;
|
|
112
|
+
})
|
|
113
|
+
.remove();
|
|
114
|
+
}
|
|
115
|
+
return axisItem;
|
|
50
116
|
});
|
|
51
|
-
|
|
52
|
-
if (ticksCount) {
|
|
53
|
-
yAxisGenerator = yAxisGenerator.ticks(ticksCount);
|
|
54
|
-
}
|
|
55
|
-
svgElement.call(yAxisGenerator).attr('class', b());
|
|
56
|
-
svgElement
|
|
117
|
+
axisSelection
|
|
57
118
|
.select('.domain')
|
|
58
|
-
.attr('d',
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (!axis.labels.rotation) {
|
|
86
|
-
let elementY = 0;
|
|
87
|
-
svgElement
|
|
88
|
-
.selectAll('.tick')
|
|
89
|
-
.filter(function (_d, index) {
|
|
90
|
-
const node = this;
|
|
91
|
-
const r = node.getBoundingClientRect();
|
|
92
|
-
if (r.bottom > elementY && index !== 0) {
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
elementY = r.top - axis.labels.padding;
|
|
96
|
-
return false;
|
|
97
|
-
})
|
|
98
|
-
.remove();
|
|
99
|
-
}
|
|
100
|
-
if (axis.title.text) {
|
|
101
|
-
const textY = axis.title.margin + axis.labels.margin + axis.labels.width;
|
|
102
|
-
svgElement
|
|
103
|
-
.append('text')
|
|
104
|
-
.attr('class', b('title'))
|
|
105
|
-
.attr('text-anchor', 'middle')
|
|
106
|
-
.attr('dy', -textY)
|
|
107
|
-
.attr('dx', -height / 2)
|
|
108
|
-
.attr('font-size', axis.title.style.fontSize)
|
|
109
|
-
.attr('transform', 'rotate(-90)')
|
|
110
|
-
.text(axis.title.text)
|
|
111
|
-
.call(setEllipsisForOverflowText, height);
|
|
112
|
-
}
|
|
119
|
+
.attr('d', () => {
|
|
120
|
+
const points = [
|
|
121
|
+
[0, 0],
|
|
122
|
+
[0, height],
|
|
123
|
+
];
|
|
124
|
+
return line()(points);
|
|
125
|
+
})
|
|
126
|
+
.style('stroke', (d) => d.lineColor || '');
|
|
127
|
+
svgElement.selectAll('.tick').each((_d, index, nodes) => {
|
|
128
|
+
const tickNode = select(nodes[index]);
|
|
129
|
+
if (parseTransformStyle(tickNode.attr('transform')).y === height) {
|
|
130
|
+
// Remove stroke from tick that has the same y coordinate like domain
|
|
131
|
+
tickNode.select('line').style('stroke', 'none');
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
axisSelection
|
|
135
|
+
.append('text')
|
|
136
|
+
.attr('class', b('title'))
|
|
137
|
+
.attr('text-anchor', 'middle')
|
|
138
|
+
.attr('dy', (d) => -(d.title.margin + d.labels.margin + d.labels.width))
|
|
139
|
+
.attr('dx', (_d, index) => (index === 0 ? -height / 2 : height / 2))
|
|
140
|
+
.attr('font-size', (d) => d.title.style.fontSize)
|
|
141
|
+
.attr('transform', (_d, index) => (index === 0 ? 'rotate(-90)' : 'rotate(90)'))
|
|
142
|
+
.text((d) => d.title.text)
|
|
143
|
+
.each((_d, index, node) => {
|
|
144
|
+
return setEllipsisForOverflowText(select(node[index]), height);
|
|
145
|
+
});
|
|
113
146
|
}, [axises, width, height, scale]);
|
|
114
|
-
return React.createElement("g", { ref: ref });
|
|
147
|
+
return React.createElement("g", { ref: ref, className: b('container') });
|
|
115
148
|
};
|
|
@@ -4,7 +4,7 @@ import throttle from 'lodash/throttle';
|
|
|
4
4
|
import { block } from '../../../../utils/cn';
|
|
5
5
|
import { getD3Dispatcher } from '../d3-dispatcher';
|
|
6
6
|
import { useAxisScales, useChartDimensions, useChartOptions, useSeries, useShapes } from '../hooks';
|
|
7
|
-
import {
|
|
7
|
+
import { getYAxisWidth } from '../hooks/useChartDimensions/utils';
|
|
8
8
|
import { getPreparedXAxis } from '../hooks/useChartOptions/x-axis';
|
|
9
9
|
import { getPreparedYAxis } from '../hooks/useChartOptions/y-axis';
|
|
10
10
|
import { getClosestPoints } from '../utils/get-closest-data';
|
|
@@ -73,7 +73,8 @@ export const Chart = (props) => {
|
|
|
73
73
|
};
|
|
74
74
|
}, [dispatcher, clickHandler]);
|
|
75
75
|
const boundsOffsetTop = chart.margin.top;
|
|
76
|
-
|
|
76
|
+
// We only need to consider the width of the first left axis
|
|
77
|
+
const boundsOffsetLeft = chart.margin.left + getYAxisWidth(yAxis[0]);
|
|
77
78
|
const handleMouseMove = (event) => {
|
|
78
79
|
const [pointerX, pointerY] = pointer(event, svgRef.current);
|
|
79
80
|
const x = pointerX - boundsOffsetLeft;
|
|
@@ -97,7 +98,7 @@ export const Chart = (props) => {
|
|
|
97
98
|
React.createElement("svg", { ref: svgRef, className: b(), width: width, height: height, onMouseMove: throttledHandleMouseMove, onMouseLeave: handleMouseLeave },
|
|
98
99
|
title && React.createElement(Title, Object.assign({}, title, { chartWidth: width })),
|
|
99
100
|
React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})` },
|
|
100
|
-
xScale && yScale && (React.createElement(React.Fragment, null,
|
|
101
|
+
xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length) && (React.createElement(React.Fragment, null,
|
|
101
102
|
React.createElement(AxisY, { axises: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale }),
|
|
102
103
|
React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
|
|
103
104
|
React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale })))),
|
|
@@ -3,7 +3,7 @@ import { dateTime } from '@gravity-ui/date-utils';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../utils/cn';
|
|
5
5
|
import { formatNumber } from '../../../../shared';
|
|
6
|
-
import { getDataCategoryValue } from '../../utils';
|
|
6
|
+
import { getDataCategoryValue, getWaterfallPointSubtotal } from '../../utils';
|
|
7
7
|
const b = block('d3-tooltip');
|
|
8
8
|
const DEFAULT_DATE_FORMAT = 'DD.MM.YY';
|
|
9
9
|
const getRowData = (fieldName, axis, data) => {
|
|
@@ -30,7 +30,7 @@ const getXRowData = (xAxis, data) => getRowData('x', xAxis, data);
|
|
|
30
30
|
const getYRowData = (yAxis, data) => getRowData('y', yAxis, data);
|
|
31
31
|
const getMeasureValue = (data, xAxis, yAxis) => {
|
|
32
32
|
var _a, _b;
|
|
33
|
-
if (data.every((item) =>
|
|
33
|
+
if (data.every((item) => ['pie', 'treemap', 'waterfall'].includes(item.series.type))) {
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
if (data.some((item) => item.series.type === 'bar-y')) {
|
|
@@ -58,6 +58,23 @@ export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
|
|
|
58
58
|
React.createElement("div", { className: b('color'), style: { backgroundColor: color } }),
|
|
59
59
|
React.createElement("div", null, closest ? React.createElement("b", null, value) : React.createElement("span", null, value))));
|
|
60
60
|
}
|
|
61
|
+
case 'waterfall': {
|
|
62
|
+
const isTotal = get(data, 'total', false);
|
|
63
|
+
const subTotal = getWaterfallPointSubtotal(data, series);
|
|
64
|
+
return (React.createElement("div", { key: `${id}_${get(data, 'x')}` },
|
|
65
|
+
!isTotal && (React.createElement(React.Fragment, null,
|
|
66
|
+
React.createElement("div", { key: id, className: b('content-row') },
|
|
67
|
+
React.createElement("b", null, getXRowData(xAxis, data))),
|
|
68
|
+
React.createElement("div", { className: b('content-row') },
|
|
69
|
+
React.createElement("span", null,
|
|
70
|
+
series.name,
|
|
71
|
+
"\u00A0"),
|
|
72
|
+
React.createElement("span", null, getYRowData(yAxis, data))))),
|
|
73
|
+
React.createElement("div", { key: id, className: b('content-row') },
|
|
74
|
+
isTotal ? 'Total' : 'Subtotal',
|
|
75
|
+
": ",
|
|
76
|
+
subTotal)));
|
|
77
|
+
}
|
|
61
78
|
case 'bar-y': {
|
|
62
79
|
const value = (React.createElement(React.Fragment, null,
|
|
63
80
|
series.name,
|
|
@@ -13,6 +13,12 @@ type DefaultBarYSeriesOptions = Partial<ChartKitWidgetSeriesOptions['bar-x']> &
|
|
|
13
13
|
groupPadding: number;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
type DefaultWaterfallSeriesOptions = Partial<ChartKitWidgetSeriesOptions['waterfall']> & {
|
|
17
|
+
waterfall: {
|
|
18
|
+
barMaxWidth: number;
|
|
19
|
+
barPadding: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export type SeriesOptionsDefaults = Partial<ChartKitWidgetSeriesOptions> & DefaultBarXSeriesOptions & DefaultBarYSeriesOptions & DefaultWaterfallSeriesOptions;
|
|
17
23
|
export declare const seriesOptionsDefaults: SeriesOptionsDefaults;
|
|
18
24
|
export {};
|
|
@@ -89,4 +89,18 @@ export const seriesOptionsDefaults = {
|
|
|
89
89
|
},
|
|
90
90
|
},
|
|
91
91
|
},
|
|
92
|
+
waterfall: {
|
|
93
|
+
barMaxWidth: 50,
|
|
94
|
+
barPadding: 0.1,
|
|
95
|
+
states: {
|
|
96
|
+
hover: {
|
|
97
|
+
enabled: true,
|
|
98
|
+
brightness: 0.3,
|
|
99
|
+
},
|
|
100
|
+
inactive: {
|
|
101
|
+
enabled: false,
|
|
102
|
+
opacity: 0.5,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
92
106
|
};
|
|
@@ -12,7 +12,7 @@ type Args = {
|
|
|
12
12
|
};
|
|
13
13
|
type ReturnValue = {
|
|
14
14
|
xScale?: ChartScale;
|
|
15
|
-
yScale?: ChartScale;
|
|
15
|
+
yScale?: ChartScale[];
|
|
16
16
|
};
|
|
17
17
|
export declare function createYScale(axis: PreparedAxis, series: PreparedSeries[], boundsHeight: number): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
|
|
18
18
|
export declare function createXScale(axis: PreparedAxis | ChartKitWidgetAxis, series: (PreparedSeries | ChartKitWidgetSeries)[], boundsWidth: number): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
|
|
@@ -135,7 +135,14 @@ const createScales = (args) => {
|
|
|
135
135
|
visibleSeries = visibleSeries.length === 0 ? series : visibleSeries;
|
|
136
136
|
return {
|
|
137
137
|
xScale: createXScale(xAxis, visibleSeries, boundsWidth),
|
|
138
|
-
yScale:
|
|
138
|
+
yScale: yAxis.map((axis, index) => {
|
|
139
|
+
const axisSeries = series.filter((s) => {
|
|
140
|
+
const seriesAxisIndex = get(s, 'yAxis', 0);
|
|
141
|
+
return seriesAxisIndex === index;
|
|
142
|
+
});
|
|
143
|
+
const visibleAxisSeries = getOnlyVisibleSeries(axisSeries);
|
|
144
|
+
return createYScale(axis, visibleAxisSeries.length ? visibleAxisSeries : axisSeries, boundsHeight);
|
|
145
|
+
}),
|
|
139
146
|
};
|
|
140
147
|
};
|
|
141
148
|
/**
|
|
@@ -4,6 +4,7 @@ export declare const getBoundsWidth: (args: {
|
|
|
4
4
|
chartMargin: PreparedChart['margin'];
|
|
5
5
|
preparedYAxis: PreparedAxis[];
|
|
6
6
|
}) => number;
|
|
7
|
+
export declare function getYAxisWidth(axis: PreparedAxis | undefined): number;
|
|
7
8
|
export declare function getWidthOccupiedByYAxis(args: {
|
|
8
9
|
preparedAxis: PreparedAxis[];
|
|
9
10
|
}): number;
|
|
@@ -5,16 +5,17 @@ export const getBoundsWidth = (args) => {
|
|
|
5
5
|
chartMargin.left -
|
|
6
6
|
getWidthOccupiedByYAxis({ preparedAxis: preparedYAxis }));
|
|
7
7
|
};
|
|
8
|
-
export function
|
|
9
|
-
const { preparedAxis } = args;
|
|
8
|
+
export function getYAxisWidth(axis) {
|
|
10
9
|
let result = 0;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
});
|
|
10
|
+
if (axis === null || axis === void 0 ? void 0 : axis.title.text) {
|
|
11
|
+
result += axis.title.height + axis.title.margin;
|
|
12
|
+
}
|
|
13
|
+
if (axis === null || axis === void 0 ? void 0 : axis.labels.enabled) {
|
|
14
|
+
result += axis.labels.margin + axis.labels.width;
|
|
15
|
+
}
|
|
19
16
|
return result;
|
|
20
17
|
}
|
|
18
|
+
export function getWidthOccupiedByYAxis(args) {
|
|
19
|
+
const { preparedAxis = [] } = args;
|
|
20
|
+
return preparedAxis.reduce((sum, axis) => sum + getYAxisWidth(axis), 0);
|
|
21
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import { DEFAULT_AXIS_LABEL_FONT_SIZE, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
3
|
-
import { formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, } from '../../utils';
|
|
3
|
+
import { formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, getWaterfallPointSubtotal, } from '../../utils';
|
|
4
4
|
import { createYScale } from '../useAxisScales';
|
|
5
5
|
const getAxisLabelMaxWidth = (args) => {
|
|
6
6
|
const { axis, series } = args;
|
|
@@ -24,61 +24,77 @@ const getAxisLabelMaxWidth = (args) => {
|
|
|
24
24
|
};
|
|
25
25
|
function getAxisMin(axis, series) {
|
|
26
26
|
const min = axis === null || axis === void 0 ? void 0 : axis.min;
|
|
27
|
-
const seriesWithVolume = ['bar-x', 'area'];
|
|
27
|
+
const seriesWithVolume = ['bar-x', 'area', 'waterfall'];
|
|
28
28
|
if (typeof min === 'undefined' && (series === null || series === void 0 ? void 0 : series.some((s) => seriesWithVolume.includes(s.type)))) {
|
|
29
|
-
return
|
|
29
|
+
return series.reduce((minValue, s) => {
|
|
30
|
+
switch (s.type) {
|
|
31
|
+
case 'waterfall': {
|
|
32
|
+
const minSubTotal = s.data.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, s) || 0), 0);
|
|
33
|
+
return Math.min(minValue, minSubTotal);
|
|
34
|
+
}
|
|
35
|
+
default: {
|
|
36
|
+
return minValue;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, 0);
|
|
30
40
|
}
|
|
31
41
|
return min;
|
|
32
42
|
}
|
|
33
43
|
export const getPreparedYAxis = ({ series, yAxis, }) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
44
|
+
return (yAxis || [{}]).map((axisItem, index) => {
|
|
45
|
+
const axisPosition = index === 0 ? 'left' : 'right';
|
|
46
|
+
const labelsEnabled = get(axisItem, 'labels.enabled', true);
|
|
47
|
+
const labelsStyle = {
|
|
48
|
+
fontSize: get(axisItem, 'labels.style.fontSize', DEFAULT_AXIS_LABEL_FONT_SIZE),
|
|
49
|
+
};
|
|
50
|
+
const titleText = get(axisItem, 'title.text', '');
|
|
51
|
+
const titleStyle = {
|
|
52
|
+
fontSize: get(axisItem, 'title.style.fontSize', yAxisTitleDefaults.fontSize),
|
|
53
|
+
};
|
|
54
|
+
const axisType = get(axisItem, 'type', 'linear');
|
|
55
|
+
const preparedAxis = {
|
|
56
|
+
type: axisType,
|
|
57
|
+
labels: {
|
|
58
|
+
enabled: labelsEnabled,
|
|
59
|
+
margin: labelsEnabled
|
|
60
|
+
? get(axisItem, 'labels.margin', axisLabelsDefaults.margin)
|
|
61
|
+
: 0,
|
|
62
|
+
padding: labelsEnabled
|
|
63
|
+
? get(axisItem, 'labels.padding', axisLabelsDefaults.padding)
|
|
64
|
+
: 0,
|
|
65
|
+
dateFormat: get(axisItem, 'labels.dateFormat'),
|
|
66
|
+
numberFormat: get(axisItem, 'labels.numberFormat'),
|
|
67
|
+
style: labelsStyle,
|
|
68
|
+
rotation: get(axisItem, 'labels.rotation', 0),
|
|
69
|
+
width: 0,
|
|
70
|
+
height: 0,
|
|
71
|
+
lineHeight: getHorisontalSvgTextHeight({ text: 'TmpLabel', style: labelsStyle }),
|
|
72
|
+
maxWidth: get(axisItem, 'labels.maxWidth', axisLabelsDefaults.maxWidth),
|
|
73
|
+
},
|
|
74
|
+
lineColor: get(axisItem, 'lineColor'),
|
|
75
|
+
categories: get(axisItem, 'categories'),
|
|
76
|
+
timestamps: get(axisItem, 'timestamps'),
|
|
77
|
+
title: {
|
|
78
|
+
text: titleText,
|
|
79
|
+
margin: get(axisItem, 'title.margin', yAxisTitleDefaults.margin),
|
|
80
|
+
style: titleStyle,
|
|
81
|
+
height: titleText
|
|
82
|
+
? getHorisontalSvgTextHeight({ text: titleText, style: titleStyle })
|
|
83
|
+
: 0,
|
|
84
|
+
},
|
|
85
|
+
min: getAxisMin(axisItem, series),
|
|
86
|
+
maxPadding: get(axisItem, 'maxPadding', 0.05),
|
|
87
|
+
grid: {
|
|
88
|
+
enabled: get(axisItem, 'grid.enabled', index === 0),
|
|
89
|
+
},
|
|
90
|
+
ticks: {
|
|
91
|
+
pixelInterval: get(axisItem, 'ticks.pixelInterval'),
|
|
92
|
+
},
|
|
93
|
+
position: axisPosition,
|
|
94
|
+
};
|
|
95
|
+
if (labelsEnabled) {
|
|
96
|
+
preparedAxis.labels.width = getAxisLabelMaxWidth({ axis: preparedAxis, series });
|
|
97
|
+
}
|
|
98
|
+
return preparedAxis;
|
|
99
|
+
});
|
|
84
100
|
};
|
|
@@ -5,9 +5,9 @@ export declare const DEFAULT_LINE_WIDTH = 1;
|
|
|
5
5
|
export declare const DEFAULT_MARKER: {
|
|
6
6
|
enabled: boolean;
|
|
7
7
|
symbol: "circle" | "diamond" | "square" | "triangle" | "triangle-down";
|
|
8
|
-
radius: number;
|
|
9
8
|
borderColor: string;
|
|
10
9
|
borderWidth: number;
|
|
10
|
+
radius: number;
|
|
11
11
|
};
|
|
12
12
|
type PrepareAreaSeriesArgs = {
|
|
13
13
|
colorScale: ScaleOrdinal<string, string>;
|