Skip to content

Commit c439d67

Browse files
authored
Merge pull request #1558 from FormidableLabs/task/add-chart-background-primitive
VictoryChart: adds an option for adding background for chart area
2 parents 8c08a31 + ee88dbd commit c439d67

File tree

12 files changed

+241
-38
lines changed

12 files changed

+241
-38
lines changed

demo/js/components/victory-chart-demo.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,30 @@ class App extends React.Component {
180180
alignItems: "center",
181181
justifyContent: "center"
182182
};
183-
const chartStyle = { parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" } };
183+
const chartStyle = {
184+
parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" }
185+
};
184186
const axisStyle = {
185187
grid: { stroke: "grey", strokeWidth: 1 },
186188
axis: { stroke: "transparent" },
187189
ticks: { stroke: "transparent" },
188190
tickLabels: { fill: "none" }
189191
};
192+
193+
const bgStyle = {
194+
background: { fill: "#e6e6ff" }
195+
};
196+
190197
return (
191198
<div className="demo">
192199
<h1>VictoryChart</h1>
193200
<div style={containerStyle}>
194-
<VictoryChart style={chartStyle}>
195-
<VictoryScatter data={[{ x: -3, y: -3 }]} />
201+
<VictoryChart style={chartStyle} polar>
202+
<VictoryScatter />
203+
</VictoryChart>
204+
205+
<VictoryChart style={assign({}, chartStyle, bgStyle)}>
206+
<VictoryScatter data={[{ x: -3, y: -3 }, { x: -2, y: 2 }, { x: 1, y: -1 }]} />
196207
</VictoryChart>
197208

198209
<VictoryChart style={chartStyle} theme={dependentAxisTheme}>

demo/ts/components/victory-chart-demo.tsx

+17-4
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,32 @@ class VictoryChartDemo extends React.Component<any, VictoryChartDemoState> {
208208
alignItems: "center",
209209
justifyContent: "center"
210210
};
211-
const chartStyle = { parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" } };
212-
const axisStyle = {
211+
212+
const chartStyle: { [key: string]: React.CSSProperties } = {
213+
parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" }
214+
};
215+
216+
const axisStyle: { [key: string]: React.CSSProperties } = {
213217
grid: { stroke: "grey", strokeWidth: 1 },
214218
axis: { stroke: "transparent" },
215219
ticks: { stroke: "transparent" },
216220
tickLabels: { fill: "none" }
217221
};
222+
223+
const bgStyle: { [key: string]: React.CSSProperties } = {
224+
background: { fill: "#e6e6ff" }
225+
};
226+
218227
return (
219228
<div className="demo">
220229
<h1>VictoryChart</h1>
221230
<div style={containerStyle}>
222-
<VictoryChart style={chartStyle}>
223-
<VictoryScatter data={[{ x: -3, y: -3 }]} />
231+
<VictoryChart style={chartStyle} polar>
232+
<VictoryScatter />
233+
</VictoryChart>
234+
235+
<VictoryChart style={assign({}, chartStyle, bgStyle)}>
236+
<VictoryScatter data={[{ x: -3, y: -3 }, { x: -2, y: 2 }, { x: 1, y: -1 }]} />
224237
</VictoryChart>
225238

226239
<VictoryChart style={chartStyle} theme={dependentAxisTheme}>

demo/ts/components/victory-polar-axis-demo.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { VictoryScatter } from "@packages/victory-scatter";
1010
import { VictoryZoomContainer } from "@packages/victory-zoom-container";
1111
import { VictoryVoronoiContainer } from "@packages/victory-voronoi-container";
1212
import { random, range, keys } from "lodash";
13-
import { VictoryTheme, VictoryLabel, VictoryStyleInterface } from "@packages/victory-core";
13+
import { VictoryTheme, VictoryLabel } from "@packages/victory-core";
1414

1515
type multiAxisDataListType = {
1616
strength?: number;
@@ -115,7 +115,7 @@ class App extends React.Component<any, VictoryPolarAxisState> {
115115
justifyContent: "center"
116116
};
117117

118-
const chartStyle: VictoryStyleInterface = {
118+
const chartStyle: { [key: string]: React.CSSProperties } = {
119119
parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" }
120120
};
121121

packages/victory-chart/src/helper-methods.js

+52-13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,40 @@ function getAxisProps(child, props, calculatedProps) {
3636
};
3737
}
3838

39+
function getBackgroundWithProps(props, calculatedProps) {
40+
const backgroundElement = props.backgroundComponent;
41+
42+
const height = props.polar
43+
? calculatedProps.range.y[1]
44+
: calculatedProps.range.y[0] - calculatedProps.range.y[1];
45+
const width = calculatedProps.range.x[1] - calculatedProps.range.x[0];
46+
47+
const xScale = props.horizontal
48+
? calculatedProps.scale.y.range()[0]
49+
: calculatedProps.scale.x.range()[0];
50+
const yScale = props.horizontal
51+
? calculatedProps.scale.x.range()[1]
52+
: calculatedProps.scale.y.range()[1];
53+
54+
const xCoordinate = props.polar ? calculatedProps.origin.x : xScale;
55+
const yCoordinate = props.polar ? calculatedProps.origin.y : yScale;
56+
57+
const backgroundProps = {
58+
height,
59+
polar: props.polar,
60+
scale: calculatedProps.scale,
61+
style: props.style.background,
62+
x: xCoordinate,
63+
y: yCoordinate,
64+
width
65+
};
66+
67+
return React.cloneElement(
68+
backgroundElement,
69+
defaults({}, backgroundElement.props, backgroundProps)
70+
);
71+
}
72+
3973
function getChildProps(child, props, calculatedProps) {
4074
const axisChild = Axis.findAxisComponents([child]);
4175
if (axisChild.length > 0) {
@@ -47,6 +81,7 @@ function getChildProps(child, props, calculatedProps) {
4781

4882
function getStyles(props) {
4983
const styleProps = props.style && props.style.parent;
84+
5085
return {
5186
parent: defaults({}, styleProps, {
5287
height: "100%",
@@ -129,6 +164,7 @@ function getChildren(props, childComponents, calculatedProps) {
129164
const { height, polar, theme, width } = props;
130165
const { origin, horizontal } = calculatedProps;
131166
const parentName = props.name || "chart";
167+
132168
return childComponents.map((child, index) => {
133169
const role = child.type && child.type.role;
134170
const style = Array.isArray(child.props.style)
@@ -158,21 +194,24 @@ function getChildren(props, childComponents, calculatedProps) {
158194

159195
const getChildComponents = (props, defaultAxes) => {
160196
const childComponents = React.Children.toArray(props.children);
161-
if (childComponents.length === 0) {
162-
return [defaultAxes.independent, defaultAxes.dependent];
163-
}
197+
let newChildComponents = [...childComponents];
164198

165-
const axisComponents = {
166-
dependent: Axis.getAxisComponentsWithParent(childComponents, "dependent"),
167-
independent: Axis.getAxisComponentsWithParent(childComponents, "independent")
168-
};
199+
if (childComponents.length === 0) {
200+
newChildComponents.push(defaultAxes.independent, defaultAxes.dependent);
201+
} else {
202+
const axisComponents = {
203+
dependent: Axis.getAxisComponentsWithParent(childComponents, "dependent"),
204+
independent: Axis.getAxisComponentsWithParent(childComponents, "independent")
205+
};
169206

170-
if (axisComponents.dependent.length === 0 && axisComponents.independent.length === 0) {
171-
return props.prependDefaultAxes
172-
? [defaultAxes.independent, defaultAxes.dependent].concat(childComponents)
173-
: childComponents.concat([defaultAxes.independent, defaultAxes.dependent]);
207+
if (axisComponents.dependent.length === 0 && axisComponents.independent.length === 0) {
208+
newChildComponents = props.prependDefaultAxes
209+
? [defaultAxes.independent, defaultAxes.dependent].concat(newChildComponents)
210+
: newChildComponents.concat([defaultAxes.independent, defaultAxes.dependent]);
211+
}
174212
}
175-
return childComponents;
213+
214+
return newChildComponents;
176215
};
177216

178217
const getDomain = (props, axis, childComponents) => {
@@ -252,4 +291,4 @@ const createStringMap = (props, childComponents) => {
252291
return { x, y };
253292
};
254293

255-
export { getChildren, getCalculatedProps, getChildComponents };
294+
export { getBackgroundWithProps, getChildren, getCalculatedProps, getChildComponents };

packages/victory-chart/src/index.d.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
import * as React from "react";
22
import {
33
CategoryPropType,
4-
EventPropTypeInterface,
54
DomainPropType,
5+
EventPropTypeInterface,
66
StringOrNumberOrCallback,
77
VictoryCommonProps,
8-
VictoryStyleInterface
8+
VictoryStyleInterface,
9+
VictoryStyleObject
910
} from "victory-core";
1011

1112
export type AxesType = {
12-
independent?: React.ReactElement;
1313
dependent?: React.ReactElement;
14+
independent?: React.ReactElement;
1415
};
1516

1617
export interface VictoryChartProps extends VictoryCommonProps {
17-
defaultAxes?: AxesType;
18-
defaultPolarAxes?: AxesType;
1918
categories?: CategoryPropType;
2019
children?: React.ReactNode | React.ReactNode[];
20+
defaultAxes?: AxesType;
21+
defaultPolarAxes?: AxesType;
2122
domain?: DomainPropType;
2223
endAngle?: number;
23-
events?: EventPropTypeInterface<string, string[] | number[] | string | number>[];
2424
eventKey?: StringOrNumberOrCallback;
25+
events?: EventPropTypeInterface<string, string[] | number[] | string | number>[];
2526
innerRadius?: number;
2627
prependDefaultAxes?: boolean;
2728
startAngle?: number;
28-
style?: Pick<VictoryStyleInterface, "parent">;
29+
style?: Pick<VictoryStyleInterface, "parent"> & { background?: VictoryStyleObject };
2930
}
3031

3132
export class VictoryChart extends React.Component<VictoryChartProps, any> {}

packages/victory-chart/src/victory-chart.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { defaults, assign, isEmpty } from "lodash";
22
import PropTypes from "prop-types";
33
import React from "react";
44
import {
5+
Background,
56
Helpers,
67
VictoryContainer,
78
VictoryTheme,
@@ -12,7 +13,12 @@ import {
1213
import { VictorySharedEvents } from "victory-shared-events";
1314
import { VictoryAxis } from "victory-axis";
1415
import { VictoryPolarAxis } from "victory-polar-axis";
15-
import { getChildComponents, getCalculatedProps, getChildren } from "./helper-methods";
16+
import {
17+
getBackgroundWithProps,
18+
getChildComponents,
19+
getCalculatedProps,
20+
getChildren
21+
} from "./helper-methods";
1622
import isEqual from "react-fast-compare";
1723

1824
const fallbackProps = {
@@ -26,6 +32,7 @@ export default class VictoryChart extends React.Component {
2632

2733
static propTypes = {
2834
...CommonProps.baseProps,
35+
backgroundComponent: PropTypes.element,
2936
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
3037
defaultAxes: PropTypes.shape({
3138
independent: PropTypes.element,
@@ -42,6 +49,7 @@ export default class VictoryChart extends React.Component {
4249
};
4350

4451
static defaultProps = {
52+
backgroundComponent: <Background />,
4553
containerComponent: <VictoryContainer />,
4654
defaultAxes: {
4755
independent: <VictoryAxis />,
@@ -84,10 +92,19 @@ export default class VictoryChart extends React.Component {
8492
getNewChildren(props, childComponents, calculatedProps) {
8593
const children = getChildren(props, childComponents, calculatedProps);
8694
const getAnimationProps = Wrapper.getAnimationProps.bind(this);
87-
return children.map((child, index) => {
95+
96+
const newChildren = children.map((child, index) => {
8897
const childProps = assign({ animate: getAnimationProps(props, child, index) }, child.props);
8998
return React.cloneElement(child, childProps);
9099
});
100+
101+
if (props.style && props.style.background) {
102+
const backgroundComponent = getBackgroundWithProps(props, calculatedProps);
103+
104+
newChildren.unshift(backgroundComponent);
105+
}
106+
107+
return newChildren;
91108
}
92109

93110
renderContainer(containerComponent, props) {
@@ -134,6 +151,7 @@ export default class VictoryChart extends React.Component {
134151
? this.renderContainer(containerComponent, containerProps)
135152
: groupComponent;
136153
const events = Wrapper.getAllEvents(props);
154+
137155
if (!isEmpty(events)) {
138156
return (
139157
<VictorySharedEvents

packages/victory-core/src/index.d.ts

+11
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,17 @@ export class VictoryPortal extends React.Component<VictoryPortalProps, any> {}
660660

661661
// #region Victory Primitives
662662

663+
export interface BackgroundProps extends VictoryCommonPrimitiveProps {
664+
circleComponent?: React.ReactElement;
665+
height?: number;
666+
rectComponent?: React.ReactElement;
667+
width?: number;
668+
x?: number;
669+
y?: number;
670+
}
671+
672+
export class Background extends React.Component<BackgroundProps> {}
673+
663674
export interface VictoryPointProps extends VictoryCommonPrimitiveProps {
664675
datum?: any;
665676
getPath?: Function;

packages/victory-core/src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export { default as VictoryTheme } from "./victory-theme/victory-theme";
77
export { default as VictoryPortal } from "./victory-portal/victory-portal";
88
export { default as Portal } from "./victory-portal/portal";
99
export { default as Arc } from "./victory-primitives/arc";
10+
export { default as Background } from "./victory-primitives/background";
1011
export { default as Border, default as Box } from "./victory-primitives/border";
1112
export { default as ClipPath } from "./victory-primitives/clip-path";
1213
export { default as LineSegment } from "./victory-primitives/line-segment";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import CommonProps from "../victory-util/common-props";
4+
import Rect from "./rect";
5+
import Circle from "./circle";
6+
7+
const Background = (props) => {
8+
return props.polar
9+
? React.cloneElement(props.circleComponent, {
10+
...props.events,
11+
style: props.style,
12+
role: props.role,
13+
shapeRendering: props.shapeRendering,
14+
cx: props.x,
15+
cy: props.y,
16+
r: props.height
17+
})
18+
: React.cloneElement(props.rectComponent, {
19+
...props.events,
20+
style: props.style,
21+
role: props.role,
22+
shapeRendering: props.shapeRendering,
23+
x: props.x,
24+
y: props.y,
25+
width: props.width,
26+
height: props.height
27+
});
28+
};
29+
30+
Background.propTypes = {
31+
...CommonProps.primitiveProps,
32+
circleComponent: PropTypes.element,
33+
height: PropTypes.number,
34+
rectComponent: PropTypes.element,
35+
width: PropTypes.number,
36+
x: PropTypes.number,
37+
y: PropTypes.number
38+
};
39+
40+
Background.defaultProps = {
41+
circleComponent: <Circle />,
42+
rectComponent: <Rect />,
43+
role: "presentation",
44+
shapeRendering: "auto"
45+
};
46+
47+
export default Background;

packages/victory/src/index.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
declare module "victory" {
55
import {
6+
Background,
67
// Border,
78
// Box,
89
// ClipPath,
@@ -115,6 +116,7 @@ declare module "victory" {
115116

116117
export {
117118
// Area,
119+
Background,
118120
// Bar,
119121
// Border,
120122
// Box,

packages/victory/src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
Background,
23
Border,
34
Box,
45
ClipPath,
@@ -87,6 +88,7 @@ import { VictoryPolarAxis } from "victory-polar-axis";
8788

8889
export {
8990
Area,
91+
Background,
9092
Bar,
9193
Border,
9294
Box,

0 commit comments

Comments
 (0)