@gravity-ui/charts 1.30.0 → 1.30.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.
@@ -251,7 +251,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
251
251
  plotBands.push({
252
252
  layerPlacement: plotBand.layerPlacement,
253
253
  x: Math.max(0, startPos),
254
- y: 0,
254
+ y: axisTop,
255
255
  width: plotBandWidth,
256
256
  height: axisHeight,
257
257
  color: plotBand.color,
@@ -294,7 +294,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
294
294
  plotLines.push({
295
295
  layerPlacement: plotLine.layerPlacement,
296
296
  x: 0,
297
- y: 0,
297
+ y: axisTop,
298
298
  width: axisWidth,
299
299
  color: plotLine.color,
300
300
  opacity: plotLine.opacity,
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
- import { line as lineGenerator, scaleLinear, select, symbol } from 'd3';
2
+ import { scaleLinear, select, symbol } from 'd3';
3
3
  import { CONTINUOUS_LEGEND_SIZE } from '../../constants';
4
4
  import { formatNumber } from '../../libs';
5
- import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getLineDashArray, getSymbol, getUniqId, handleOverflowingText, } from '../../utils';
5
+ import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getSymbol, getUniqId, handleOverflowingText, } from '../../utils';
6
6
  import { axisBottom } from '../../utils/chart/axis-generators';
7
+ import { appendLinePathElement } from '../utils';
7
8
  import './styles.css';
8
9
  const b = block('legend');
9
10
  const getLegendItemLeftPosition = (args) => {
@@ -64,9 +65,6 @@ const appendPaginator = (args) => {
64
65
  });
65
66
  paginationLine.attr('transform', transform);
66
67
  };
67
- const legendSymbolGenerator = lineGenerator()
68
- .x((d) => d.x)
69
- .y((d) => d.y);
70
68
  function renderLegendSymbol(args) {
71
69
  const { selection, legend, legendLineHeight } = args;
72
70
  const line = selection.data();
@@ -86,21 +84,16 @@ function renderLegendSymbol(args) {
86
84
  const color = d.visible ? d.color : '';
87
85
  switch (d.symbol.shape) {
88
86
  case 'path': {
89
- const y = legendLineHeight / 2;
90
- const points = [
91
- { x, y },
92
- { x: x + d.symbol.width, y },
93
- ];
94
- element
95
- .append('path')
96
- .attr('d', legendSymbolGenerator(points))
97
- .attr('fill', 'none')
98
- .attr('stroke-width', d.symbol.strokeWidth)
99
- .attr('class', className)
100
- .style('stroke', color);
101
- if (d.dashStyle) {
102
- element.attr('stroke-dasharray', getLineDashArray(d.dashStyle, d.symbol.strokeWidth));
103
- }
87
+ appendLinePathElement({
88
+ svgRootElement: element.node(),
89
+ x,
90
+ height: legendLineHeight,
91
+ width: d.symbol.width,
92
+ color,
93
+ className,
94
+ dashStyle: d.dashStyle,
95
+ lineWidth: d.symbol.strokeWidth,
96
+ });
104
97
  break;
105
98
  }
106
99
  case 'rect': {
@@ -4,6 +4,7 @@ export declare function Row(props: {
4
4
  active?: boolean;
5
5
  className?: string;
6
6
  color?: string;
7
+ colorSymbol?: React.ReactNode;
7
8
  striped?: boolean;
8
9
  style?: React.CSSProperties;
9
10
  value?: React.ReactNode;
@@ -2,9 +2,18 @@ import React from 'react';
2
2
  import { block } from '../../../utils';
3
3
  const b = block('tooltip');
4
4
  export function Row(props) {
5
- const { label, value, active, color, className, striped, style } = props;
5
+ const { label, value, active, color, colorSymbol, className, striped, style } = props;
6
+ const colorItem = React.useMemo(() => {
7
+ if (colorSymbol) {
8
+ return colorSymbol;
9
+ }
10
+ if (color) {
11
+ return React.createElement("div", { className: b('content-row-color'), style: { backgroundColor: color } });
12
+ }
13
+ return null;
14
+ }, [color, colorSymbol]);
6
15
  return (React.createElement("div", { className: b('content-row', { active, striped }, className), style: style },
7
- color && React.createElement("div", { className: b('content-row-color'), style: { backgroundColor: color } }),
16
+ colorItem,
8
17
  label,
9
18
  value && React.createElement("span", { className: b('content-row-value') }, value)));
10
19
  }
@@ -8,7 +8,7 @@ import { block, hasVerticalScrollbar } from '../../../utils';
8
8
  import { getFormattedValue } from '../../../utils/chart/format';
9
9
  import { Row } from './Row';
10
10
  import { RowWithAggregation } from './RowWithAggregation';
11
- import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getXRowData, } from './utils';
11
+ import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getTooltipRowColorSymbol, getXRowData, } from './utils';
12
12
  const b = block('tooltip');
13
13
  export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, qa, }) => {
14
14
  var _a;
@@ -21,7 +21,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
21
21
  const prevHoveredValues = usePrevious(hoveredValues);
22
22
  const visibleHovered = pinned || !visibleRows ? hovered : hovered.slice(0, visibleRows);
23
23
  const restHoveredValues = pinned || !visibleRows ? [] : hoveredValues.slice(visibleRows);
24
- const renderRow = ({ id, name, color, active, striped, value, formattedValue, }) => {
24
+ const renderRow = ({ id, name, color, active, striped, value, formattedValue, series, }) => {
25
25
  if (typeof rowRenderer === 'function') {
26
26
  return rowRenderer({
27
27
  id,
@@ -35,7 +35,8 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
35
35
  hovered,
36
36
  });
37
37
  }
38
- return (React.createElement(Row, { key: id, active: active, color: color, label: React.createElement("span", { dangerouslySetInnerHTML: { __html: name } }), striped: striped, value: formattedValue }));
38
+ const colorSymbol = getTooltipRowColorSymbol({ series, color });
39
+ return (React.createElement(Row, { key: id, active: active, color: color, colorSymbol: colorSymbol ? (React.createElement("div", { dangerouslySetInnerHTML: { __html: colorSymbol.outerHTML } })) : undefined, label: React.createElement("span", { dangerouslySetInnerHTML: { __html: name } }), striped: striped, value: formattedValue }));
39
40
  };
40
41
  const formattedHeadValue = headerFormat
41
42
  ? getFormattedValue({
@@ -113,6 +114,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
113
114
  striped,
114
115
  value: hoveredValues[i],
115
116
  formattedValue,
117
+ series,
116
118
  });
117
119
  }
118
120
  case 'waterfall': {
@@ -35,3 +35,9 @@ export declare function getPreparedAggregation(args: {
35
35
  xAxis?: ChartXAxis | null;
36
36
  yAxis?: ChartYAxis;
37
37
  }): ChartTooltipTotalsBuiltInAggregation | (() => ChartTooltipTotalsAggregationValue);
38
+ export declare function getTooltipRowColorSymbol({ series, color, height, width, }: {
39
+ color?: string;
40
+ series?: TooltipDataChunk['series'];
41
+ height?: number;
42
+ width?: number;
43
+ }): SVGSVGElement | null;
@@ -1,7 +1,9 @@
1
+ import { create } from 'd3-selection';
1
2
  import get from 'lodash/get';
2
3
  import { i18n } from '../../../i18n';
3
4
  import { getDataCategoryValue, getDefaultDateFormat } from '../../../utils';
4
5
  import { getFormattedValue } from '../../../utils/chart/format';
6
+ import { appendLinePathElement } from '../../utils';
5
7
  function getRowData(fieldName, data, axis) {
6
8
  switch (axis === null || axis === void 0 ? void 0 : axis.type) {
7
9
  case 'category': {
@@ -128,3 +130,19 @@ export function getPreparedAggregation(args) {
128
130
  }
129
131
  return 'sum';
130
132
  }
133
+ export function getTooltipRowColorSymbol({ series, color, height = 8, width = 16, }) {
134
+ if ((series === null || series === void 0 ? void 0 : series.type) === 'line') {
135
+ const colorSymbol = create('svg').attr('height', height).attr('width', width);
136
+ const g = colorSymbol.append('g');
137
+ appendLinePathElement({
138
+ svgRootElement: g.node(),
139
+ height,
140
+ width,
141
+ color,
142
+ dashStyle: get(series, 'dashStyle'),
143
+ lineWidth: get(series, 'lineWidth'),
144
+ });
145
+ return colorSymbol.node();
146
+ }
147
+ return null;
148
+ }
@@ -1,3 +1,4 @@
1
+ import type { DashStyle } from '../constants';
1
2
  import type { ChartScaleLinear, ChartScaleTime } from '../hooks';
2
3
  import type { ChartAxisRangeSlider } from '../types';
3
4
  export declare function getInitialRangeSliderState(args: {
@@ -7,3 +8,13 @@ export declare function getInitialRangeSliderState(args: {
7
8
  min: number;
8
9
  max: number;
9
10
  };
11
+ export declare function appendLinePathElement({ svgRootElement, height, width, x, lineWidth, dashStyle, className, color, }: {
12
+ svgRootElement: SVGGElement | null;
13
+ height: number;
14
+ width: number;
15
+ x?: number;
16
+ lineWidth?: number;
17
+ dashStyle?: DashStyle;
18
+ className?: string;
19
+ color?: string;
20
+ }): import("d3-selection").Selection<SVGGElement | null, unknown, null, undefined>;
@@ -1,5 +1,7 @@
1
1
  import { duration } from '@gravity-ui/date-utils';
2
- import { isTimeScale } from '../utils';
2
+ import { line as lineGenerator } from 'd3';
3
+ import { select } from 'd3-selection';
4
+ import { getLineDashArray, isTimeScale } from '../utils';
3
5
  export function getInitialRangeSliderState(args) {
4
6
  const { defaultRange, xScale } = args;
5
7
  let minRange;
@@ -32,3 +34,25 @@ export function getInitialRangeSliderState(args) {
32
34
  }
33
35
  return { min: minRange, max: maxRange };
34
36
  }
37
+ const legendSymbolGenerator = lineGenerator()
38
+ .x((d) => d.x)
39
+ .y((d) => d.y);
40
+ export function appendLinePathElement({ svgRootElement, height, width, x = 0, lineWidth = 1, dashStyle, className, color, }) {
41
+ const rootELementSelection = select(svgRootElement);
42
+ const y = height / 2;
43
+ const points = [
44
+ { x, y },
45
+ { x: x + width, y },
46
+ ];
47
+ const pathElement = rootELementSelection
48
+ .append('path')
49
+ .attr('d', legendSymbolGenerator(points))
50
+ .attr('fill', 'none')
51
+ .attr('stroke-width', lineWidth)
52
+ .attr('class', className !== null && className !== void 0 ? className : null)
53
+ .style('stroke', color !== null && color !== void 0 ? color : '');
54
+ if (dashStyle) {
55
+ pathElement.attr('stroke-dasharray', getLineDashArray(dashStyle, lineWidth));
56
+ }
57
+ return rootELementSelection;
58
+ }
@@ -251,7 +251,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
251
251
  plotBands.push({
252
252
  layerPlacement: plotBand.layerPlacement,
253
253
  x: Math.max(0, startPos),
254
- y: 0,
254
+ y: axisTop,
255
255
  width: plotBandWidth,
256
256
  height: axisHeight,
257
257
  color: plotBand.color,
@@ -294,7 +294,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
294
294
  plotLines.push({
295
295
  layerPlacement: plotLine.layerPlacement,
296
296
  x: 0,
297
- y: 0,
297
+ y: axisTop,
298
298
  width: axisWidth,
299
299
  color: plotLine.color,
300
300
  opacity: plotLine.opacity,
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
- import { line as lineGenerator, scaleLinear, select, symbol } from 'd3';
2
+ import { scaleLinear, select, symbol } from 'd3';
3
3
  import { CONTINUOUS_LEGEND_SIZE } from '../../constants';
4
4
  import { formatNumber } from '../../libs';
5
- import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getLineDashArray, getSymbol, getUniqId, handleOverflowingText, } from '../../utils';
5
+ import { block, createGradientRect, getContinuesColorFn, getLabelsSize, getSymbol, getUniqId, handleOverflowingText, } from '../../utils';
6
6
  import { axisBottom } from '../../utils/chart/axis-generators';
7
+ import { appendLinePathElement } from '../utils';
7
8
  import './styles.css';
8
9
  const b = block('legend');
9
10
  const getLegendItemLeftPosition = (args) => {
@@ -64,9 +65,6 @@ const appendPaginator = (args) => {
64
65
  });
65
66
  paginationLine.attr('transform', transform);
66
67
  };
67
- const legendSymbolGenerator = lineGenerator()
68
- .x((d) => d.x)
69
- .y((d) => d.y);
70
68
  function renderLegendSymbol(args) {
71
69
  const { selection, legend, legendLineHeight } = args;
72
70
  const line = selection.data();
@@ -86,21 +84,16 @@ function renderLegendSymbol(args) {
86
84
  const color = d.visible ? d.color : '';
87
85
  switch (d.symbol.shape) {
88
86
  case 'path': {
89
- const y = legendLineHeight / 2;
90
- const points = [
91
- { x, y },
92
- { x: x + d.symbol.width, y },
93
- ];
94
- element
95
- .append('path')
96
- .attr('d', legendSymbolGenerator(points))
97
- .attr('fill', 'none')
98
- .attr('stroke-width', d.symbol.strokeWidth)
99
- .attr('class', className)
100
- .style('stroke', color);
101
- if (d.dashStyle) {
102
- element.attr('stroke-dasharray', getLineDashArray(d.dashStyle, d.symbol.strokeWidth));
103
- }
87
+ appendLinePathElement({
88
+ svgRootElement: element.node(),
89
+ x,
90
+ height: legendLineHeight,
91
+ width: d.symbol.width,
92
+ color,
93
+ className,
94
+ dashStyle: d.dashStyle,
95
+ lineWidth: d.symbol.strokeWidth,
96
+ });
104
97
  break;
105
98
  }
106
99
  case 'rect': {
@@ -4,6 +4,7 @@ export declare function Row(props: {
4
4
  active?: boolean;
5
5
  className?: string;
6
6
  color?: string;
7
+ colorSymbol?: React.ReactNode;
7
8
  striped?: boolean;
8
9
  style?: React.CSSProperties;
9
10
  value?: React.ReactNode;
@@ -2,9 +2,18 @@ import React from 'react';
2
2
  import { block } from '../../../utils';
3
3
  const b = block('tooltip');
4
4
  export function Row(props) {
5
- const { label, value, active, color, className, striped, style } = props;
5
+ const { label, value, active, color, colorSymbol, className, striped, style } = props;
6
+ const colorItem = React.useMemo(() => {
7
+ if (colorSymbol) {
8
+ return colorSymbol;
9
+ }
10
+ if (color) {
11
+ return React.createElement("div", { className: b('content-row-color'), style: { backgroundColor: color } });
12
+ }
13
+ return null;
14
+ }, [color, colorSymbol]);
6
15
  return (React.createElement("div", { className: b('content-row', { active, striped }, className), style: style },
7
- color && React.createElement("div", { className: b('content-row-color'), style: { backgroundColor: color } }),
16
+ colorItem,
8
17
  label,
9
18
  value && React.createElement("span", { className: b('content-row-value') }, value)));
10
19
  }
@@ -8,7 +8,7 @@ import { block, hasVerticalScrollbar } from '../../../utils';
8
8
  import { getFormattedValue } from '../../../utils/chart/format';
9
9
  import { Row } from './Row';
10
10
  import { RowWithAggregation } from './RowWithAggregation';
11
- import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getXRowData, } from './utils';
11
+ import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getTooltipRowColorSymbol, getXRowData, } from './utils';
12
12
  const b = block('tooltip');
13
13
  export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, qa, }) => {
14
14
  var _a;
@@ -21,7 +21,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
21
21
  const prevHoveredValues = usePrevious(hoveredValues);
22
22
  const visibleHovered = pinned || !visibleRows ? hovered : hovered.slice(0, visibleRows);
23
23
  const restHoveredValues = pinned || !visibleRows ? [] : hoveredValues.slice(visibleRows);
24
- const renderRow = ({ id, name, color, active, striped, value, formattedValue, }) => {
24
+ const renderRow = ({ id, name, color, active, striped, value, formattedValue, series, }) => {
25
25
  if (typeof rowRenderer === 'function') {
26
26
  return rowRenderer({
27
27
  id,
@@ -35,7 +35,8 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
35
35
  hovered,
36
36
  });
37
37
  }
38
- return (React.createElement(Row, { key: id, active: active, color: color, label: React.createElement("span", { dangerouslySetInnerHTML: { __html: name } }), striped: striped, value: formattedValue }));
38
+ const colorSymbol = getTooltipRowColorSymbol({ series, color });
39
+ return (React.createElement(Row, { key: id, active: active, color: color, colorSymbol: colorSymbol ? (React.createElement("div", { dangerouslySetInnerHTML: { __html: colorSymbol.outerHTML } })) : undefined, label: React.createElement("span", { dangerouslySetInnerHTML: { __html: name } }), striped: striped, value: formattedValue }));
39
40
  };
40
41
  const formattedHeadValue = headerFormat
41
42
  ? getFormattedValue({
@@ -113,6 +114,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
113
114
  striped,
114
115
  value: hoveredValues[i],
115
116
  formattedValue,
117
+ series,
116
118
  });
117
119
  }
118
120
  case 'waterfall': {
@@ -35,3 +35,9 @@ export declare function getPreparedAggregation(args: {
35
35
  xAxis?: ChartXAxis | null;
36
36
  yAxis?: ChartYAxis;
37
37
  }): ChartTooltipTotalsBuiltInAggregation | (() => ChartTooltipTotalsAggregationValue);
38
+ export declare function getTooltipRowColorSymbol({ series, color, height, width, }: {
39
+ color?: string;
40
+ series?: TooltipDataChunk['series'];
41
+ height?: number;
42
+ width?: number;
43
+ }): SVGSVGElement | null;
@@ -1,7 +1,9 @@
1
+ import { create } from 'd3-selection';
1
2
  import get from 'lodash/get';
2
3
  import { i18n } from '../../../i18n';
3
4
  import { getDataCategoryValue, getDefaultDateFormat } from '../../../utils';
4
5
  import { getFormattedValue } from '../../../utils/chart/format';
6
+ import { appendLinePathElement } from '../../utils';
5
7
  function getRowData(fieldName, data, axis) {
6
8
  switch (axis === null || axis === void 0 ? void 0 : axis.type) {
7
9
  case 'category': {
@@ -128,3 +130,19 @@ export function getPreparedAggregation(args) {
128
130
  }
129
131
  return 'sum';
130
132
  }
133
+ export function getTooltipRowColorSymbol({ series, color, height = 8, width = 16, }) {
134
+ if ((series === null || series === void 0 ? void 0 : series.type) === 'line') {
135
+ const colorSymbol = create('svg').attr('height', height).attr('width', width);
136
+ const g = colorSymbol.append('g');
137
+ appendLinePathElement({
138
+ svgRootElement: g.node(),
139
+ height,
140
+ width,
141
+ color,
142
+ dashStyle: get(series, 'dashStyle'),
143
+ lineWidth: get(series, 'lineWidth'),
144
+ });
145
+ return colorSymbol.node();
146
+ }
147
+ return null;
148
+ }
@@ -1,3 +1,4 @@
1
+ import type { DashStyle } from '../constants';
1
2
  import type { ChartScaleLinear, ChartScaleTime } from '../hooks';
2
3
  import type { ChartAxisRangeSlider } from '../types';
3
4
  export declare function getInitialRangeSliderState(args: {
@@ -7,3 +8,13 @@ export declare function getInitialRangeSliderState(args: {
7
8
  min: number;
8
9
  max: number;
9
10
  };
11
+ export declare function appendLinePathElement({ svgRootElement, height, width, x, lineWidth, dashStyle, className, color, }: {
12
+ svgRootElement: SVGGElement | null;
13
+ height: number;
14
+ width: number;
15
+ x?: number;
16
+ lineWidth?: number;
17
+ dashStyle?: DashStyle;
18
+ className?: string;
19
+ color?: string;
20
+ }): import("d3-selection").Selection<SVGGElement | null, unknown, null, undefined>;
@@ -1,5 +1,7 @@
1
1
  import { duration } from '@gravity-ui/date-utils';
2
- import { isTimeScale } from '../utils';
2
+ import { line as lineGenerator } from 'd3';
3
+ import { select } from 'd3-selection';
4
+ import { getLineDashArray, isTimeScale } from '../utils';
3
5
  export function getInitialRangeSliderState(args) {
4
6
  const { defaultRange, xScale } = args;
5
7
  let minRange;
@@ -32,3 +34,25 @@ export function getInitialRangeSliderState(args) {
32
34
  }
33
35
  return { min: minRange, max: maxRange };
34
36
  }
37
+ const legendSymbolGenerator = lineGenerator()
38
+ .x((d) => d.x)
39
+ .y((d) => d.y);
40
+ export function appendLinePathElement({ svgRootElement, height, width, x = 0, lineWidth = 1, dashStyle, className, color, }) {
41
+ const rootELementSelection = select(svgRootElement);
42
+ const y = height / 2;
43
+ const points = [
44
+ { x, y },
45
+ { x: x + width, y },
46
+ ];
47
+ const pathElement = rootELementSelection
48
+ .append('path')
49
+ .attr('d', legendSymbolGenerator(points))
50
+ .attr('fill', 'none')
51
+ .attr('stroke-width', lineWidth)
52
+ .attr('class', className !== null && className !== void 0 ? className : null)
53
+ .style('stroke', color !== null && color !== void 0 ? color : '');
54
+ if (dashStyle) {
55
+ pathElement.attr('stroke-dasharray', getLineDashArray(dashStyle, lineWidth));
56
+ }
57
+ return rootELementSelection;
58
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.30.0",
3
+ "version": "1.30.1",
4
4
  "description": "A flexible JavaScript library for data visualization and chart rendering using React",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",