@gravity-ui/charts 1.13.0 → 1.13.1

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.
@@ -4,13 +4,15 @@ type DefaultBarXSeriesOptions = Partial<ChartSeriesOptions['bar-x']> & {
4
4
  barMaxWidth: number;
5
5
  barPadding: number;
6
6
  groupPadding: number;
7
+ stackGap: number;
7
8
  };
8
9
  };
9
- type DefaultBarYSeriesOptions = Partial<ChartSeriesOptions['bar-x']> & {
10
+ type DefaultBarYSeriesOptions = Partial<ChartSeriesOptions['bar-y']> & {
10
11
  'bar-y': {
11
12
  barMaxWidth: number;
12
13
  barPadding: number;
13
14
  groupPadding: number;
15
+ stackGap: number;
14
16
  };
15
17
  };
16
18
  type DefaultWaterfallSeriesOptions = Partial<ChartSeriesOptions['waterfall']> & {
@@ -3,6 +3,7 @@ export const seriesOptionsDefaults = {
3
3
  barMaxWidth: 50,
4
4
  barPadding: 0.1,
5
5
  groupPadding: 0.2,
6
+ stackGap: 1,
6
7
  states: {
7
8
  hover: {
8
9
  enabled: true,
@@ -18,6 +19,7 @@ export const seriesOptionsDefaults = {
18
19
  barMaxWidth: 50,
19
20
  barPadding: 0.1,
20
21
  groupPadding: 0.2,
22
+ stackGap: 1,
21
23
  states: {
22
24
  hover: {
23
25
  enabled: true,
@@ -32,6 +32,7 @@ async function getLabelData(d) {
32
32
  }
33
33
  export const prepareBarXData = async (args) => {
34
34
  const { series, seriesOptions, xAxis, xScale, yScale, boundsHeight: plotHeight } = args;
35
+ const stackGap = seriesOptions['bar-x'].stackGap;
35
36
  const categories = get(xAxis, 'categories', []);
36
37
  const barMaxWidth = get(seriesOptions, 'bar-x.barMaxWidth');
37
38
  const barPadding = get(seriesOptions, 'bar-x.barPadding');
@@ -124,7 +125,12 @@ export const prepareBarXData = async (args) => {
124
125
  const yDataValue = yValue.data.y;
125
126
  const y = seriesYScale(yDataValue);
126
127
  const base = seriesYScale(0);
128
+ const isLastStackItem = yValueIndex === sortedData.length - 1;
127
129
  const height = yDataValue > 0 ? base - y : y - base;
130
+ let shapeHeight = height - (stackItems.length ? stackGap : 0);
131
+ if (shapeHeight < 0) {
132
+ shapeHeight = height;
133
+ }
128
134
  if (height <= 0) {
129
135
  continue;
130
136
  }
@@ -132,12 +138,12 @@ export const prepareBarXData = async (args) => {
132
138
  x,
133
139
  y: yDataValue > 0 ? y - stackHeight : seriesYScale(0),
134
140
  width: rectWidth,
135
- height,
141
+ height: shapeHeight,
136
142
  opacity: get(yValue.data, 'opacity', null),
137
143
  data: yValue.data,
138
144
  series: yValue.series,
139
145
  htmlElements: [],
140
- isLastStackItem: yValueIndex === sortedData.length - 1,
146
+ isLastStackItem,
141
147
  };
142
148
  const label = await getLabelData(barData);
143
149
  if (yValue.series.dataLabels.html && label) {
@@ -153,7 +159,7 @@ export const prepareBarXData = async (args) => {
153
159
  barData.label = await getLabelData(barData);
154
160
  }
155
161
  stackItems.push(barData);
156
- stackHeight += height + 1;
162
+ stackHeight += height;
157
163
  }
158
164
  if (series.some((s) => s.stacking === 'percent')) {
159
165
  let acc = 0;
@@ -7,10 +7,10 @@ const DEFAULT_LABEL_PADDING = 7;
7
7
  export const prepareBarYData = async (args) => {
8
8
  var _a;
9
9
  const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
10
+ const stackGap = seriesOptions['bar-y'].stackGap;
10
11
  const xLinearScale = xScale;
11
12
  const yLinearScale = yScale;
12
13
  const plotHeight = yLinearScale(yLinearScale.domain()[0]);
13
- const plotWidth = xLinearScale(xLinearScale.domain()[1]);
14
14
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
15
15
  const comparator = (sortingOptions === null || sortingOptions === void 0 ? void 0 : sortingOptions.direction) === 'desc' ? descending : ascending;
16
16
  const sortKey = (() => {
@@ -46,6 +46,16 @@ export const prepareBarYData = async (args) => {
46
46
  const sortedData = sortKey
47
47
  ? sort(measureValues, (a, b) => comparator(get(a, sortKey), get(b, sortKey)))
48
48
  : measureValues;
49
+ let ratio = 1;
50
+ if (series.some((s) => s.stacking === 'percent')) {
51
+ const sum = sortedData.reduce((acc, item) => {
52
+ if (item.data.x) {
53
+ return acc + xLinearScale(Number(item.data.x));
54
+ }
55
+ return acc;
56
+ }, 0);
57
+ ratio = xLinearScale.range()[1] / sum;
58
+ }
49
59
  sortedData.forEach(({ data, series: s }, xValueIndex) => {
50
60
  let center;
51
61
  if (yAxis[0].type === 'category') {
@@ -58,14 +68,20 @@ export const prepareBarYData = async (args) => {
58
68
  }
59
69
  const y = center - currentBarHeight / 2 + (barSize + barGap) * groupItemIndex;
60
70
  const xValue = Number(data.x);
61
- const width = Math.abs(xLinearScale(xValue) - base);
62
- if (width <= 0) {
71
+ const isLastStackItem = xValueIndex === sortedData.length - 1;
72
+ const width = Math.abs(xLinearScale(xValue) * ratio - base);
73
+ let shapeWidth = width - (stackItems.length ? stackGap : 0);
74
+ if (shapeWidth < 0) {
75
+ shapeWidth = width;
76
+ }
77
+ if (shapeWidth <= 0) {
63
78
  return;
64
79
  }
80
+ const itemStackGap = width - shapeWidth;
65
81
  const item = {
66
- x: xValue > baseRangeValue ? stackSum : stackSum - width,
67
- y,
68
- width,
82
+ x: (xValue > baseRangeValue ? stackSum : stackSum - width) + itemStackGap,
83
+ y: y,
84
+ width: shapeWidth,
69
85
  height: barSize,
70
86
  color: data.color || s.color,
71
87
  borderColor: s.borderColor,
@@ -73,20 +89,11 @@ export const prepareBarYData = async (args) => {
73
89
  opacity: get(data, 'opacity', null),
74
90
  data,
75
91
  series: s,
76
- isLastStackItem: xValueIndex === sortedData.length - 1,
92
+ isLastStackItem,
77
93
  };
78
94
  stackItems.push(item);
79
- stackSum += width + 1;
95
+ stackSum += width;
80
96
  });
81
- if (series.some((s) => s.stacking === 'percent')) {
82
- let acc = 0;
83
- const ratio = plotWidth / (stackSum - stackItems.length);
84
- stackItems.forEach((item) => {
85
- item.width = item.width * ratio;
86
- item.x = acc;
87
- acc += item.width;
88
- });
89
- }
90
97
  result.push(...stackItems);
91
98
  });
92
99
  });
@@ -79,6 +79,11 @@ export interface ChartSeriesOptions {
79
79
  * @default 0
80
80
  */
81
81
  borderRadius?: number;
82
+ /**
83
+ * The distance between the shapes of the stacked values, in pixels.
84
+ * @default 1
85
+ */
86
+ stackGap?: number;
82
87
  dataSorting?: {
83
88
  /** Determines what data value should be used to sort by.
84
89
  * Possible values are undefined to disable, "name" to sort by series name or "y"
@@ -130,6 +135,11 @@ export interface ChartSeriesOptions {
130
135
  * @default 0
131
136
  */
132
137
  borderRadius?: number;
138
+ /**
139
+ * The distance between the shapes of the stacked values, in pixels.
140
+ * @default 1
141
+ */
142
+ stackGap?: number;
133
143
  dataSorting?: {
134
144
  /** Determines what data value should be used to sort by.
135
145
  * Possible values are undefined to disable, "name" to sort by series name or "x"
@@ -4,13 +4,15 @@ type DefaultBarXSeriesOptions = Partial<ChartSeriesOptions['bar-x']> & {
4
4
  barMaxWidth: number;
5
5
  barPadding: number;
6
6
  groupPadding: number;
7
+ stackGap: number;
7
8
  };
8
9
  };
9
- type DefaultBarYSeriesOptions = Partial<ChartSeriesOptions['bar-x']> & {
10
+ type DefaultBarYSeriesOptions = Partial<ChartSeriesOptions['bar-y']> & {
10
11
  'bar-y': {
11
12
  barMaxWidth: number;
12
13
  barPadding: number;
13
14
  groupPadding: number;
15
+ stackGap: number;
14
16
  };
15
17
  };
16
18
  type DefaultWaterfallSeriesOptions = Partial<ChartSeriesOptions['waterfall']> & {
@@ -3,6 +3,7 @@ export const seriesOptionsDefaults = {
3
3
  barMaxWidth: 50,
4
4
  barPadding: 0.1,
5
5
  groupPadding: 0.2,
6
+ stackGap: 1,
6
7
  states: {
7
8
  hover: {
8
9
  enabled: true,
@@ -18,6 +19,7 @@ export const seriesOptionsDefaults = {
18
19
  barMaxWidth: 50,
19
20
  barPadding: 0.1,
20
21
  groupPadding: 0.2,
22
+ stackGap: 1,
21
23
  states: {
22
24
  hover: {
23
25
  enabled: true,
@@ -32,6 +32,7 @@ async function getLabelData(d) {
32
32
  }
33
33
  export const prepareBarXData = async (args) => {
34
34
  const { series, seriesOptions, xAxis, xScale, yScale, boundsHeight: plotHeight } = args;
35
+ const stackGap = seriesOptions['bar-x'].stackGap;
35
36
  const categories = get(xAxis, 'categories', []);
36
37
  const barMaxWidth = get(seriesOptions, 'bar-x.barMaxWidth');
37
38
  const barPadding = get(seriesOptions, 'bar-x.barPadding');
@@ -124,7 +125,12 @@ export const prepareBarXData = async (args) => {
124
125
  const yDataValue = yValue.data.y;
125
126
  const y = seriesYScale(yDataValue);
126
127
  const base = seriesYScale(0);
128
+ const isLastStackItem = yValueIndex === sortedData.length - 1;
127
129
  const height = yDataValue > 0 ? base - y : y - base;
130
+ let shapeHeight = height - (stackItems.length ? stackGap : 0);
131
+ if (shapeHeight < 0) {
132
+ shapeHeight = height;
133
+ }
128
134
  if (height <= 0) {
129
135
  continue;
130
136
  }
@@ -132,12 +138,12 @@ export const prepareBarXData = async (args) => {
132
138
  x,
133
139
  y: yDataValue > 0 ? y - stackHeight : seriesYScale(0),
134
140
  width: rectWidth,
135
- height,
141
+ height: shapeHeight,
136
142
  opacity: get(yValue.data, 'opacity', null),
137
143
  data: yValue.data,
138
144
  series: yValue.series,
139
145
  htmlElements: [],
140
- isLastStackItem: yValueIndex === sortedData.length - 1,
146
+ isLastStackItem,
141
147
  };
142
148
  const label = await getLabelData(barData);
143
149
  if (yValue.series.dataLabels.html && label) {
@@ -153,7 +159,7 @@ export const prepareBarXData = async (args) => {
153
159
  barData.label = await getLabelData(barData);
154
160
  }
155
161
  stackItems.push(barData);
156
- stackHeight += height + 1;
162
+ stackHeight += height;
157
163
  }
158
164
  if (series.some((s) => s.stacking === 'percent')) {
159
165
  let acc = 0;
@@ -7,10 +7,10 @@ const DEFAULT_LABEL_PADDING = 7;
7
7
  export const prepareBarYData = async (args) => {
8
8
  var _a;
9
9
  const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
10
+ const stackGap = seriesOptions['bar-y'].stackGap;
10
11
  const xLinearScale = xScale;
11
12
  const yLinearScale = yScale;
12
13
  const plotHeight = yLinearScale(yLinearScale.domain()[0]);
13
- const plotWidth = xLinearScale(xLinearScale.domain()[1]);
14
14
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
15
15
  const comparator = (sortingOptions === null || sortingOptions === void 0 ? void 0 : sortingOptions.direction) === 'desc' ? descending : ascending;
16
16
  const sortKey = (() => {
@@ -46,6 +46,16 @@ export const prepareBarYData = async (args) => {
46
46
  const sortedData = sortKey
47
47
  ? sort(measureValues, (a, b) => comparator(get(a, sortKey), get(b, sortKey)))
48
48
  : measureValues;
49
+ let ratio = 1;
50
+ if (series.some((s) => s.stacking === 'percent')) {
51
+ const sum = sortedData.reduce((acc, item) => {
52
+ if (item.data.x) {
53
+ return acc + xLinearScale(Number(item.data.x));
54
+ }
55
+ return acc;
56
+ }, 0);
57
+ ratio = xLinearScale.range()[1] / sum;
58
+ }
49
59
  sortedData.forEach(({ data, series: s }, xValueIndex) => {
50
60
  let center;
51
61
  if (yAxis[0].type === 'category') {
@@ -58,14 +68,20 @@ export const prepareBarYData = async (args) => {
58
68
  }
59
69
  const y = center - currentBarHeight / 2 + (barSize + barGap) * groupItemIndex;
60
70
  const xValue = Number(data.x);
61
- const width = Math.abs(xLinearScale(xValue) - base);
62
- if (width <= 0) {
71
+ const isLastStackItem = xValueIndex === sortedData.length - 1;
72
+ const width = Math.abs(xLinearScale(xValue) * ratio - base);
73
+ let shapeWidth = width - (stackItems.length ? stackGap : 0);
74
+ if (shapeWidth < 0) {
75
+ shapeWidth = width;
76
+ }
77
+ if (shapeWidth <= 0) {
63
78
  return;
64
79
  }
80
+ const itemStackGap = width - shapeWidth;
65
81
  const item = {
66
- x: xValue > baseRangeValue ? stackSum : stackSum - width,
67
- y,
68
- width,
82
+ x: (xValue > baseRangeValue ? stackSum : stackSum - width) + itemStackGap,
83
+ y: y,
84
+ width: shapeWidth,
69
85
  height: barSize,
70
86
  color: data.color || s.color,
71
87
  borderColor: s.borderColor,
@@ -73,20 +89,11 @@ export const prepareBarYData = async (args) => {
73
89
  opacity: get(data, 'opacity', null),
74
90
  data,
75
91
  series: s,
76
- isLastStackItem: xValueIndex === sortedData.length - 1,
92
+ isLastStackItem,
77
93
  };
78
94
  stackItems.push(item);
79
- stackSum += width + 1;
95
+ stackSum += width;
80
96
  });
81
- if (series.some((s) => s.stacking === 'percent')) {
82
- let acc = 0;
83
- const ratio = plotWidth / (stackSum - stackItems.length);
84
- stackItems.forEach((item) => {
85
- item.width = item.width * ratio;
86
- item.x = acc;
87
- acc += item.width;
88
- });
89
- }
90
97
  result.push(...stackItems);
91
98
  });
92
99
  });
@@ -79,6 +79,11 @@ export interface ChartSeriesOptions {
79
79
  * @default 0
80
80
  */
81
81
  borderRadius?: number;
82
+ /**
83
+ * The distance between the shapes of the stacked values, in pixels.
84
+ * @default 1
85
+ */
86
+ stackGap?: number;
82
87
  dataSorting?: {
83
88
  /** Determines what data value should be used to sort by.
84
89
  * Possible values are undefined to disable, "name" to sort by series name or "y"
@@ -130,6 +135,11 @@ export interface ChartSeriesOptions {
130
135
  * @default 0
131
136
  */
132
137
  borderRadius?: number;
138
+ /**
139
+ * The distance between the shapes of the stacked values, in pixels.
140
+ * @default 1
141
+ */
142
+ stackGap?: number;
133
143
  dataSorting?: {
134
144
  /** Determines what data value should be used to sort by.
135
145
  * Possible values are undefined to disable, "name" to sort by series name or "x"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.13.0",
3
+ "version": "1.13.1",
4
4
  "description": "React component used to render charts",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",