Skip to content

Commit 99c5e9f

Browse files
authored
feat(style): allow fill and stroke overrides (#258)
* feat(style): allow fill and stroke overrides This allows the computed series color to be overridden by the theme or the series specific style. BREAKING CHANGE: `LineStyle`, `AreaStyle` and `BarSeriesStyle` types differs on the optional values. `stroke` and `fill` on the theme or specific series style now override the computed series color. * fix: no unused locals error on theme * fix: avoid key prop override by spread operator * test: increase test coverage on PR changes * fix: fontSize is now always a number * test: increase coverage for rendendering * refactor(story): simplify theme merging on `with value label` story * refactor: removed mergeWithDefaultTheme
1 parent 90a1ba7 commit 99c5e9f

31 files changed

+1506
-901
lines changed

.playground/playgroud.tsx

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,38 @@ import {
1010
Position,
1111
ScaleType,
1212
Settings,
13+
mergeWithDefaultTheme,
1314
} from '../src';
1415
import { KIBANA_METRICS } from '../src/lib/series/utils/test_dataset_kibana';
1516

1617
export class Playground extends React.Component {
1718
render() {
18-
return (
19-
<>
20-
{this.renderChart(Position.Right)}
21-
{this.renderChart(Position.Bottom)}
22-
</>
23-
);
19+
return <>{this.renderChart(Position.Right)}</>;
2420
}
2521
renderChart(legendPosition: Position) {
22+
const theme = mergeWithDefaultTheme({
23+
lineSeriesStyle: {
24+
// area: {
25+
// fill: 'green',
26+
// opacity:0.2
27+
// },
28+
line: {
29+
stroke: 'violet',
30+
strokeWidth: 4,
31+
},
32+
point: {
33+
fill: 'yellow',
34+
stroke: 'black',
35+
strokeWidth: 2,
36+
radius: 6,
37+
},
38+
},
39+
});
40+
console.log(theme.areaSeriesStyle);
2641
return (
2742
<div className="chart">
2843
<Chart>
29-
<Settings debug={true} showLegend={true} legendPosition={legendPosition} rotation={0} />
44+
<Settings debug={false} showLegend={true} legendPosition={legendPosition} rotation={0} theme={theme} />
3045
<Axis
3146
id={getAxisId('timestamp')}
3247
title="timestamp"
@@ -40,6 +55,12 @@ export class Playground extends React.Component {
4055
yScaleType={ScaleType.Linear}
4156
data={KIBANA_METRICS.metrics.kibana_os_load[0].data.slice(0, 15)}
4257
xAccessor={0}
58+
lineSeriesStyle={{
59+
line: {
60+
stroke: 'red',
61+
opacity: 1,
62+
},
63+
}}
4364
yAccessors={[1]}
4465
/>
4566
<LineSeries
@@ -49,30 +70,7 @@ export class Playground extends React.Component {
4970
data={KIBANA_METRICS.metrics.kibana_os_load[1].data.slice(0, 15)}
5071
xAccessor={0}
5172
yAccessors={[1]}
52-
/>
53-
<LineSeries
54-
id={getSpecId('dataset C')}
55-
xScaleType={ScaleType.Time}
56-
yScaleType={ScaleType.Linear}
57-
data={KIBANA_METRICS.metrics.kibana_os_load[2].data.slice(0, 15)}
58-
xAccessor={0}
59-
yAccessors={[1]}
60-
/>
61-
<LineSeries
62-
id={getSpecId('dataset D')}
63-
xScaleType={ScaleType.Time}
64-
yScaleType={ScaleType.Linear}
65-
data={KIBANA_METRICS.metrics.kibana_os_load[1].data.slice(0, 15)}
66-
xAccessor={0}
67-
yAccessors={[1]}
68-
/>
69-
<LineSeries
70-
id={getSpecId('dataset E')}
71-
xScaleType={ScaleType.Time}
72-
yScaleType={ScaleType.Linear}
73-
data={KIBANA_METRICS.metrics.kibana_os_load[1].data.slice(0, 15)}
74-
xAccessor={0}
75-
yAccessors={[1]}
73+
stackAccessors={[0]}
7674
/>
7775
</Chart>
7876
</div>

src/components/react_canvas/area_geometries.tsx

Lines changed: 46 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ import { Circle, Group, Path } from 'react-konva';
44
import { animated, Spring } from 'react-spring/renderprops-konva.cjs';
55
import { LegendItem } from '../../lib/series/legend';
66
import { AreaGeometry, getGeometryStyle, PointGeometry } from '../../lib/series/rendering';
7-
import { AreaSeriesStyle, SharedGeometryStyle } from '../../lib/themes/theme';
7+
import { SharedGeometryStyle } from '../../lib/themes/theme';
88
import {
9-
buildAreaLineProps,
10-
buildAreaPointProps,
11-
buildAreaProps,
9+
buildAreaRenderProps,
1210
buildPointStyleProps,
11+
buildPointRenderProps,
12+
PointStyleProps,
13+
buildLineRenderProps,
1314
} from './utils/rendering_props_utils';
1415

1516
interface AreaGeometriesDataProps {
1617
animated?: boolean;
1718
areas: AreaGeometry[];
18-
style: AreaSeriesStyle;
1919
sharedStyle: SharedGeometryStyle;
2020
highlightedLegendItem: LegendItem | null;
2121
}
@@ -35,171 +35,113 @@ export class AreaGeometries extends React.PureComponent<AreaGeometriesDataProps,
3535
};
3636
}
3737
render() {
38-
const { point, area, line } = this.props.style;
39-
4038
return (
4139
<Group ref={this.barSeriesRef} key={'bar_series'}>
42-
{this.renderAreaGeoms(area.visible)}
43-
{this.renderAreaLines(line.visible)}
44-
{this.renderAreaPoints(point.visible)}
40+
{this.renderAreaGeoms()}
41+
{this.renderAreaLines()}
42+
{this.renderAreaPoints()}
4543
</Group>
4644
);
4745
}
48-
private renderAreaPoints = (themeIsVisible: boolean): JSX.Element[] => {
46+
private renderAreaPoints = (): JSX.Element[] => {
4947
const { areas } = this.props;
5048
return areas.reduce(
5149
(acc, glyph, i) => {
52-
const { points, seriesPointStyle } = glyph;
50+
const { points, seriesPointStyle, color } = glyph;
5351

54-
const isVisible = seriesPointStyle ? seriesPointStyle.visible : themeIsVisible;
55-
if (!isVisible) {
52+
if (!seriesPointStyle.visible) {
5653
return acc;
5754
}
5855

59-
const { radius, strokeWidth, opacity } = this.props.style.point;
60-
const pointStyleProps = buildPointStyleProps({
61-
radius,
62-
strokeWidth,
63-
opacity,
64-
seriesPointStyle,
65-
});
56+
const pointStyleProps = buildPointStyleProps(color, seriesPointStyle);
6657

6758
return [...acc, ...this.renderPoints(points, i, pointStyleProps)];
6859
},
6960
[] as JSX.Element[],
7061
);
7162
};
72-
private renderPoints = (areaPoints: PointGeometry[], areaIndex: number, pointStyleProps: any): JSX.Element[] => {
63+
private renderPoints = (
64+
areaPoints: PointGeometry[],
65+
areaIndex: number,
66+
pointStyleProps: PointStyleProps,
67+
): JSX.Element[] => {
7368
const areaPointElements: JSX.Element[] = [];
69+
7470
areaPoints.forEach((areaPoint, pointIndex) => {
75-
const { x, y, color, transform } = areaPoint;
71+
const { x, y, transform } = areaPoint;
72+
const key = `area-point-${areaIndex}-${pointIndex}`;
7673

7774
if (this.props.animated) {
7875
areaPointElements.push(
7976
<Group key={`area-point-group-${areaIndex}-${pointIndex}`} x={transform.x}>
8077
<Spring native from={{ y }} to={{ y }}>
8178
{() => {
82-
const pointProps = buildAreaPointProps({
83-
areaIndex,
84-
pointIndex,
85-
x,
86-
y,
87-
color,
88-
pointStyleProps,
89-
});
90-
return <animated.Circle {...pointProps} />;
79+
const pointProps = buildPointRenderProps(x, y, pointStyleProps);
80+
return <animated.Circle {...pointProps} key={key} />;
9181
}}
9282
</Spring>
9383
</Group>,
9484
);
9585
} else {
96-
const pointProps = buildAreaPointProps({
97-
areaIndex,
98-
pointIndex,
99-
x: transform.x + x,
100-
y,
101-
color,
102-
pointStyleProps,
103-
});
104-
areaPointElements.push(<Circle {...pointProps} />);
86+
const pointProps = buildPointRenderProps(transform.x + x, y, pointStyleProps);
87+
areaPointElements.push(<Circle {...pointProps} key={key} />);
10588
}
10689
});
10790
return areaPointElements;
10891
};
10992

110-
private renderAreaGeoms = (themeIsVisible: boolean): JSX.Element[] => {
111-
const { areas } = this.props;
112-
const { opacity } = this.props.style.area;
93+
private renderAreaGeoms = (): JSX.Element[] => {
94+
const { areas, sharedStyle } = this.props;
11395
const areasToRender: JSX.Element[] = [];
11496

11597
areas.forEach((glyph, i) => {
116-
const { area, color, transform, seriesAreaStyle } = glyph;
117-
const isVisible = seriesAreaStyle ? seriesAreaStyle.visible : themeIsVisible;
118-
if (!isVisible) {
98+
const { area, color, transform, geometryId, seriesAreaStyle } = glyph;
99+
if (!seriesAreaStyle.visible) {
119100
return;
120101
}
121-
102+
const customOpacity = seriesAreaStyle ? seriesAreaStyle.opacity : undefined;
103+
const geometryStyle = getGeometryStyle(geometryId, this.props.highlightedLegendItem, sharedStyle, customOpacity);
104+
const key = `area-${i}`;
122105
if (this.props.animated) {
123106
areasToRender.push(
124107
<Group key={`area-group-${i}`} x={transform.x}>
125108
<Spring native from={{ area }} to={{ area }}>
126109
{(props: { area: string }) => {
127-
const areaProps = buildAreaProps({
128-
index: i,
129-
areaPath: props.area,
130-
xTransform: 0,
131-
color,
132-
opacity,
133-
seriesAreaStyle,
134-
});
135-
return <animated.Path {...areaProps} />;
110+
const areaProps = buildAreaRenderProps(0, props.area, color, seriesAreaStyle, geometryStyle);
111+
return <animated.Path {...areaProps} key={key} />;
136112
}}
137113
</Spring>
138114
</Group>,
139115
);
140116
} else {
141-
const areaProps = buildAreaProps({
142-
index: i,
143-
areaPath: area,
144-
xTransform: transform.x,
145-
color,
146-
opacity,
147-
seriesAreaStyle,
148-
});
149-
areasToRender.push(<Path {...areaProps} />);
117+
const areaProps = buildAreaRenderProps(transform.x, area, color, seriesAreaStyle, geometryStyle);
118+
areasToRender.push(<Path {...areaProps} key={key} />);
150119
}
151120
});
152121
return areasToRender;
153122
};
154-
private renderAreaLines = (themeIsVisible: boolean): JSX.Element[] => {
123+
private renderAreaLines = (): JSX.Element[] => {
155124
const { areas, sharedStyle } = this.props;
156-
const { strokeWidth } = this.props.style.line;
157125
const linesToRender: JSX.Element[] = [];
158126
areas.forEach((glyph, areaIndex) => {
159127
const { lines, color, geometryId, transform, seriesAreaLineStyle } = glyph;
160-
const isVisible = seriesAreaLineStyle ? seriesAreaLineStyle.visible : themeIsVisible;
161-
if (!isVisible) {
128+
if (!seriesAreaLineStyle.visible) {
162129
return;
163130
}
164131

165-
const customOpacity = seriesAreaLineStyle ? seriesAreaLineStyle.opacity : undefined;
166-
167-
const geometryStyle = getGeometryStyle(geometryId, this.props.highlightedLegendItem, sharedStyle, customOpacity);
132+
const geometryStyle = getGeometryStyle(
133+
geometryId,
134+
this.props.highlightedLegendItem,
135+
sharedStyle,
136+
seriesAreaLineStyle.opacity,
137+
);
168138

169139
lines.forEach((linePath, lineIndex) => {
170-
const lineProps = buildAreaLineProps({
171-
areaIndex,
172-
lineIndex,
173-
xTransform: transform.x,
174-
linePath,
175-
color,
176-
strokeWidth,
177-
geometryStyle,
178-
seriesAreaLineStyle,
179-
});
180-
linesToRender.push(<Path {...lineProps} />);
140+
const key = `area-${areaIndex}-line-${lineIndex}`;
141+
const lineProps = buildLineRenderProps(transform.x, linePath, color, seriesAreaLineStyle, geometryStyle);
142+
linesToRender.push(<Path {...lineProps} key={key} />);
181143
});
182144
});
183145
return linesToRender;
184-
// if (this.props.animated) {
185-
// return (
186-
// <Group key={`area-line-group-${i}`} x={transform.x}>
187-
// <Spring native from={{ line }} to={{ line }}>
188-
// {(props: { line: string }) => {
189-
// const lineProps = buildAreaLineProps({
190-
// index: i,
191-
// linePath: props.line,
192-
// color,
193-
// strokeWidth,
194-
// geometryStyle,
195-
// });
196-
// return <animated.Path {...lineProps} />;
197-
// }}
198-
// </Spring>
199-
// </Group>
200-
// );
201-
// } else {
202-
203-
// }
204146
};
205147
}

src/components/react_canvas/axis.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export class Axis extends React.PureComponent<AxisProps> {
9292
? getVerticalAxisTickLineProps(position, tickPadding, tickSize, tick.position)
9393
: getHorizontalAxisTickLineProps(position, tickPadding, tickSize, tick.position, maxLabelBboxHeight);
9494

95-
return <Line key={`tick-${i}`} points={lineProps} {...tickLineStyle} />;
95+
return <Line {...tickLineStyle} key={`tick-${i}`} points={lineProps} />;
9696
};
9797
private renderAxis = () => {
9898
const { ticks, axisPosition, debug } = this.props;

0 commit comments

Comments
 (0)