diff --git a/packages/data-ui-theme/src/svgLabel.js b/packages/data-ui-theme/src/svgLabel.js
index 93abdcc2..03fb3d4c 100644
--- a/packages/data-ui-theme/src/svgLabel.js
+++ b/packages/data-ui-theme/src/svgLabel.js
@@ -7,6 +7,13 @@ export const baseLabel = {
pointerEvents: 'none',
};
+export const labelTiny = {
+ ...font.tiny,
+ ...font.bold,
+ ...font.middle,
+ pointerEvents: 'none',
+};
+
export const baseTickLabel = {
...font.small,
...font.light,
diff --git a/packages/demo/examples/01-xy-chart/ScatterWithHistograms.jsx b/packages/demo/examples/01-xy-chart/ScatterWithHistograms.jsx
index c0578929..bb5dd715 100644
--- a/packages/demo/examples/01-xy-chart/ScatterWithHistograms.jsx
+++ b/packages/demo/examples/01-xy-chart/ScatterWithHistograms.jsx
@@ -59,15 +59,6 @@ function renderTooltip({ datum }) { // eslint-disable-line react/prop-types
);
}
-const RotatedLabel = ({ x, y }) => ( // eslint-disable-line react/prop-types
-
- y counts
-
-);
-
const propTypes = {
parentWidth: PropTypes.number.isRequired,
};
@@ -146,7 +137,11 @@ class ScatterWithHistogram extends React.PureComponent {
))}
}
+ label="y counts"
+ labelProps={{
+ ...theme.yAxisStyles.label.right,
+ transform: `translate(${height / 1.75}, ${height})rotate(270)`,
+ }}
/>
diff --git a/packages/demo/examples/01-xy-chart/data.js b/packages/demo/examples/01-xy-chart/data.js
index dcacaa97..e2edc3be 100644
--- a/packages/demo/examples/01-xy-chart/data.js
+++ b/packages/demo/examples/01-xy-chart/data.js
@@ -31,6 +31,62 @@ export const pointData = genRandomNormalPoints(n).map(([x, y], i) => ({
label: (i % n) === 0 ? `(${parseInt(x, 10)},${parseInt(y, 10)})` : null,
}));
+// band data
+const stdDev = 0.1;
+export const temperatureBands = groupKeys.map((city, cityIndex) => (
+ cityTemperature.slice(0, 25).map((d) => {
+ const y = Number(d[city]) - (20 * cityIndex);
+ return {
+ key: city,
+ x: d.date,
+ y,
+ y0: y + (stdDev * y),
+ y1: y - (stdDev * y),
+ };
+ })
+));
+
+export const priceBandData = {
+ band: [
+ { x: new Date('2017-06-01'), y0: 215, y1: 260 },
+ { x: new Date('2017-06-02'), y0: 203, y1: 290 },
+ { x: new Date('2017-06-03'), y0: 196, y1: 279 },
+ { x: new Date('2017-06-04'), y0: 190, y1: 261 },
+ { x: new Date('2017-06-05'), y0: 140, y1: 250 },
+ { x: new Date('2017-06-06'), y0: 120, y1: 231 },
+ { x: new Date('2017-06-07'), y0: 131, y1: 211 },
+ { x: new Date('2017-06-08'), y0: 123, y1: 196 },
+ { x: new Date('2017-06-09'), y0: 105, y1: 171 },
+ { x: new Date('2017-06-10'), y0: 100, y1: 175 },
+ { x: new Date('2017-06-11'), y0: 80, y1: 150 },
+ { x: new Date('2017-06-12'), y0: 83, y1: 164 },
+ { x: new Date('2017-06-13'), y0: 86, y1: 155 },
+ { x: new Date('2017-06-14'), y0: 80, y1: 132 },
+ { x: new Date('2017-06-15'), y0: 73, y1: 125 },
+ { x: new Date('2017-06-16'), y0: 71, y1: 132 },
+ { x: new Date('2017-06-17'), y0: 78, y1: 123 },
+ { x: new Date('2017-06-18'), y0: 82, y1: 156 },
+ { x: new Date('2017-06-19'), y0: 76, y1: 150 },
+ { x: new Date('2017-06-20'), y0: 87, y1: 173 },
+ { x: new Date('2017-06-21'), y0: 95, y1: 168 },
+ { x: new Date('2017-06-22'), y0: 105, y1: 182 },
+ { x: new Date('2017-06-23'), y0: 100, y1: 202 },
+ { x: new Date('2017-06-24'), y0: 116, y1: 211 },
+ { x: new Date('2017-06-25'), y0: 126, y1: 230 },
+ { x: new Date('2017-06-26'), y0: 137, y1: 246 },
+ { x: new Date('2017-06-27'), y0: 142, y1: 262 },
+ { x: new Date('2017-06-28'), y0: 170, y1: 273 },
+ { x: new Date('2017-06-29'), y0: 190, y1: 285 },
+ { x: new Date('2017-06-30'), y0: 201, y1: 301 },
+ ],
+};
+
+priceBandData.points = priceBandData.band.map(({ x, y0, y1 }) => ({
+ x,
+ // Introduce noise within the y0-y1 range
+ y: ((y1 + y0) / 2) + ((Math.random() > 0.5 ? -1 : 1) * Math.random() * ((y1 - y0) / 4)),
+}));
+
// interval data
const intervals = [[5, 8], [15, 19]];
diff --git a/packages/demo/examples/01-xy-chart/index.jsx b/packages/demo/examples/01-xy-chart/index.jsx
index f82f7477..03728af6 100644
--- a/packages/demo/examples/01-xy-chart/index.jsx
+++ b/packages/demo/examples/01-xy-chart/index.jsx
@@ -39,6 +39,8 @@ import {
pointData,
intervalLineData,
intervalData,
+ temperatureBands,
+ priceBandData,
} from './data';
import WithToggle from '../shared/WithToggle';
@@ -123,7 +125,7 @@ export default {
},
},
{
- description: 'AreaSeries',
+ description: 'AreaSeries -- closed',
components: [AreaSeries],
example: () => (
),
},
+ {
+ description: 'AreaSeries -- band',
+ components: [XYChart, AreaSeries, LineSeries],
+ example: () => (
+
+ {temperatureBands.map((data, i) => ([
+ ,
+ ,
+ ,
+ ]))}
+
+
+
+ ),
+ },
+ {
+ description: 'AreaSeries -- confidence intervals',
+ components: [XYChart, AreaSeries, LineSeries, PointSeries],
+ example: (reference = 150) => (
+
+
+ `$${val}`} />
+
+
+
+ (d.y >= reference ? d : { ...d, y: reference }))}
+ stroke={colors.categories[3]}
+ strokeWidth={2}
+ />
+ d.y < reference)}
+ fill="#fff"
+ fillOpacity={1}
+ stroke={colors.categories[3]}
+ />
+
+
+ ),
+ },
{
description: 'PointSeries with Histogram',
components: [PointSeries],
diff --git a/packages/demo/package.json b/packages/demo/package.json
index f70a2913..0dca11ec 100644
--- a/packages/demo/package.json
+++ b/packages/demo/package.json
@@ -55,7 +55,7 @@
"react-remarkable": "^1.1.1",
"react-with-styles": "^1.3.0",
"react-with-styles-interface-aphrodite": "^1.2.0",
- "recompose": "^0.23.5",
+ "recompose": "^0.26.0",
"style-loader": "^0.18.2"
},
"peerDependencies": {
diff --git a/packages/xy-chart/README.md b/packages/xy-chart/README.md
index 8f007bd1..d39e4b09 100644
--- a/packages/xy-chart/README.md
+++ b/packages/xy-chart/README.md
@@ -71,7 +71,7 @@ yScale | scaleShape.isRequired | - | scale config, see below.
showXGrid | PropTypes.bool | false | whether to show vertical gridlines
showYGrid | PropTypes.bool | false | whether to show vertical gridlines
theme | themeShape | false | theme shape, see below
-useVoronoi | PropTypes.bool | false | whether to compute and use a voronoi for all datapoints / mouse interactions
+useVoronoi | PropTypes.bool | false | whether to compute and use a voronoi for all datapoints (with x, y values) / mouse interactions
showVoronoi | PropTypes.bool | false | convenience prop for debugging to view the underlying voronoi if used
@@ -86,7 +86,9 @@ const scaleConfigShape = PropTypes.shape({
'band',
]).isRequired,
includeZero: PropTypes.bool,
+
// these would override any computation done by xyplot, allowing specific ranges or colors
+ // see storybook for more examples
range: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
rangeRound: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
domain: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
@@ -157,17 +159,23 @@ tickValues | PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.number, PropType
Several types of series types are exported by the package, and can be used in combination. See the storybook source for more proptables for your series of interest. Here is an overview of scale support and data shapes:
-Series | supported x scale type | supported y scale types | data shape | voronoi recommended for tooltips?
+Series | supported x scale type | supported y scale types | data shape | voronoi compatible for tooltips?
------------ | ------------- | ------- | ---- | ----
-`` | time, linear | linear | `{ x, y [, fill, stroke] }` | yes
+`` | time, linear | linear | `{ x, y [, y0, y1, fill, stroke] }`* | yes*
`` | time, linear, band | linear | `{ x, y [, fill, stroke] }` | no
`` | time, linear | linear | `{ x, y [, stroke] }` | yes
`` | time, linear | time, linear | `{ x, y [size, fill, stroke, label] }` | yes
`` | band | linear | `{ x, y }` (colors controlled with stackFills & stackKeys) | no
`` | band | linear | `{ x, y }` (colors controlled with groupFills & groupKeys) | no
-`` | time, linear | y is computed | `{ x [, size] }` | not compatible
+`` | time, linear | y is computed | `{ x [, size] }` | no
`` | time, linear | linear | `{ x0, x1 [, fill, stroke] }` | no
+\* The y boundaries of the `` may be specified by either
+ - defined `y0` and `y1` values or
+ - a single `y` value, in which case its lower bound is set to 0 (a "closed" area series)
+
+It is worth noting that voronoi overlays require a defined `y` attribute, so use of voronoi with only `y0` and `y1` values will not work.
+
#### CirclePackSeries
@@ -205,7 +213,7 @@ tooltipTimeout | PropTypes.number | 200 | Timeout in ms for the tooltip to hide
-For series components that have "small" mouse areas, such as `PointSeries` and `LineSeries`, you may opt to use an invisible Voronoi overlay on top of the visualization to increase the target area of interaction sites and improve user experience. To enable this simply set `useVoronoi` to `true` on the `` component and optionally use the convenience prop `showVoronoi` to view or debug it. Note that this will compute a voronoi layout for _all_ data points across all series.
+For series components that have "small" mouse areas, such as `PointSeries` and `LineSeries`, you may opt to use an invisible Voronoi overlay on top of the visualization to increase the target area of interaction sites and improve user experience. To enable this simply set `useVoronoi` to `true` on the `` component and optionally use the convenience prop `showVoronoi` to view or debug it. Note that this will compute a voronoi layout for _all_ data points (with defined `x` and `y` datum values!) across all series.
#### Note ‼️
Because of the polygonal shapes generated by the voronoi layout, you probably _don't_ want to use this option if you are e.g., only rendering a `BarSeries` because the bar points represent the tops of the bars and thus polygons for one bar may overlap the rect of another bar (again, you may use `showVoronoi` to debug this).
diff --git a/packages/xy-chart/package.json b/packages/xy-chart/package.json
index 4df95181..bf42b789 100644
--- a/packages/xy-chart/package.json
+++ b/packages/xy-chart/package.json
@@ -22,7 +22,7 @@
"license": "MIT",
"dependencies": {
"@data-ui/theme": "0.0.9",
- "@vx/axis": "0.0.140",
+ "@vx/axis": "0.0.145",
"@vx/curve": "0.0.140",
"@vx/event": "0.0.140",
"@vx/glyph": "0.0.140",
@@ -33,7 +33,7 @@
"@vx/point": "0.0.136",
"@vx/responsive": "0.0.140",
"@vx/scale": "0.0.140",
- "@vx/shape": "0.0.140",
+ "@vx/shape": "0.0.145",
"@vx/tooltip": "0.0.140",
"@vx/voronoi": "0.0.140",
"d3-array": "^1.2.0",
@@ -49,11 +49,13 @@
"enzyme-adapter-react-16": "^1.0.0",
"jest": "^20.0.3",
"react": "^16.0.0",
+ "react-dom": "^16.0.0",
"react-test-renderer": "^16.0.0",
"webpack": "^2.4.1"
},
"peerDependencies": {
- "react": "^15.0.0-0 || ^16.0.0-0"
+ "react": "^15.0.0-0 || ^16.0.0-0",
+ "react-dom": "^15.0.0-0 || ^16.0.0-0"
},
"jest": {
"setupFiles": [
diff --git a/packages/xy-chart/src/annotation/HorizontalReferenceLine.jsx b/packages/xy-chart/src/annotation/HorizontalReferenceLine.jsx
index 20b931d9..1593f522 100644
--- a/packages/xy-chart/src/annotation/HorizontalReferenceLine.jsx
+++ b/packages/xy-chart/src/annotation/HorizontalReferenceLine.jsx
@@ -1,12 +1,24 @@
import PropTypes from 'prop-types';
import React from 'react';
+import Group from '@vx/group/build/Group';
import Line from '@vx/shape/build/shapes/Line';
import Point from '@vx/point/build/Point';
import color from '@data-ui/theme/build/color';
+import { baseLabel } from '@data-ui/theme/build/svgLabel';
+
+export const defaultLabelProps = {
+ ...baseLabel,
+ textAnchor: 'start',
+ stroke: '#fff',
+ strokeWidth: 2,
+ paintOrder: 'stroke',
+};
export const propTypes = {
+ label: PropTypes.node,
+ labelProps: PropTypes.object,
reference: PropTypes.number.isRequired,
stroke: PropTypes.string,
strokeDasharray: PropTypes.string,
@@ -17,6 +29,8 @@ export const propTypes = {
};
const defaultProps = {
+ label: null,
+ labelProps: defaultLabelProps,
stroke: color.darkGray,
strokeDasharray: null,
strokeLinecap: 'round',
@@ -26,6 +40,8 @@ const defaultProps = {
};
function HorizontalReferenceLine({
+ label,
+ labelProps,
reference,
stroke,
strokeDasharray,
@@ -40,15 +56,18 @@ function HorizontalReferenceLine({
const fromPoint = new Point({ x: x0, y: scaledRef });
const toPoint = new Point({ x: x1, y: scaledRef });
return (
-
+
+
+ {Boolean(label) && {label}}
+
);
}
diff --git a/packages/xy-chart/src/axis/XAxis.jsx b/packages/xy-chart/src/axis/XAxis.jsx
index 2d87a8b4..f3acca01 100644
--- a/packages/xy-chart/src/axis/XAxis.jsx
+++ b/packages/xy-chart/src/axis/XAxis.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { AxisBottom, AxisTop } from '@vx/axis';
+import AxisBottom from '@vx/axis/build/axis/AxisBottom';
+import AxisTop from '@vx/axis/build/axis/AxisTop';
import { axisStylesShape, tickStylesShape } from '../utils/propShapes';
diff --git a/packages/xy-chart/src/axis/YAxis.jsx b/packages/xy-chart/src/axis/YAxis.jsx
index 691610c0..8c4c8786 100644
--- a/packages/xy-chart/src/axis/YAxis.jsx
+++ b/packages/xy-chart/src/axis/YAxis.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { AxisLeft, AxisRight } from '@vx/axis';
+import AxisLeft from '@vx/axis/build/axis/AxisLeft';
+import AxisRight from '@vx/axis/build/axis/AxisRight';
import { axisStylesShape, tickStylesShape } from '../utils/propShapes';
diff --git a/packages/xy-chart/src/chart/CrossHair.jsx b/packages/xy-chart/src/chart/CrossHair.jsx
index ca44e48b..bac53122 100644
--- a/packages/xy-chart/src/chart/CrossHair.jsx
+++ b/packages/xy-chart/src/chart/CrossHair.jsx
@@ -2,9 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import { extent } from 'd3-array';
-import { color } from '@data-ui/theme';
-import { Group } from '@vx/group';
-import { Line } from '@vx/shape';
+import color from '@data-ui/theme/build/color';
+import Group from '@vx/group/build/Group';
+import Line from '@vx/shape/build/shapes/Line';
const propTypes = {
fullHeight: PropTypes.bool,
diff --git a/packages/xy-chart/src/chart/Voronoi.jsx b/packages/xy-chart/src/chart/Voronoi.jsx
index bceb900a..75a5e971 100644
--- a/packages/xy-chart/src/chart/Voronoi.jsx
+++ b/packages/xy-chart/src/chart/Voronoi.jsx
@@ -2,8 +2,9 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Group } from '@vx/group';
-import { voronoi as voronoiLayout, VoronoiPolygon } from '@vx/voronoi';
+import Group from '@vx/group/build/Group';
+import voronoiLayout from '@vx/voronoi/build/voronoi';
+import VoronoiPolygon from '@vx/voronoi/build/components/VoronoiPolygon';
const propTypes = {
data: PropTypes.array.isRequired,
@@ -56,9 +57,7 @@ class Voronoi extends React.PureComponent {
onMouseMove={() => (event) => {
onMouseMove({ event, datum: polygon.data });
}}
- onMouseLeave={() => () => {
- onMouseLeave();
- }}
+ onMouseLeave={() => onMouseLeave}
/>
))}
diff --git a/packages/xy-chart/src/chart/XYChart.jsx b/packages/xy-chart/src/chart/XYChart.jsx
index 727c965a..a5b4cce4 100644
--- a/packages/xy-chart/src/chart/XYChart.jsx
+++ b/packages/xy-chart/src/chart/XYChart.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Grid } from '@vx/grid';
-import { Group } from '@vx/group';
+import Grid from '@vx/grid/build/grids/Grid';
+import Group from '@vx/group/build/Group';
import Voronoi from './Voronoi';
import WithTooltip, { withTooltipPropTypes } from '../enhancer/WithTooltip';
@@ -11,9 +11,10 @@ import {
collectDataFromChildSeries,
componentName,
isAxis,
+ isBarSeries,
isCirclePackSeries,
isCrossHair,
- isBarSeries,
+ isDefined,
isReferenceLine,
isSeries,
getChildWithName,
@@ -65,30 +66,38 @@ const defaultProps = {
// accessors
const getX = d => d.x;
+// if (isDefined(d.x)) return d.x;
+// else if (isDefined(d.x0 && d.x1)) return (d.x0 + d.x1) / 2;
+// return 0;
+// };
const getY = d => d.y;
-const xString = d => d.x.toString();
+// if (isDefined(d.y)) return d.y;
+// else if (isDefined(d.y0 && d.y1)) return (d.y0 + d.y1) / 2;
+// return 0;
+// };
+
+const xString = d => getX(d).toString();
class XYChart extends React.PureComponent {
static collectScalesFromProps(props) {
- const { xScale, yScale, children } = props;
+ const { xScale: xScaleObject, yScale: yScaleObject, children } = props;
const { innerWidth, innerHeight } = XYChart.getDimmensions(props);
- const { allData, dataByIndex, dataBySeriesType } = collectDataFromChildSeries(children);
- const result = { allData, dataByIndex };
+ const { allData, dataBySeriesType } = collectDataFromChildSeries(children);
- result.xScale = getScaleForAccessor({
+ const xScale = getScaleForAccessor({
allData,
minAccessor: d => (typeof d.x0 !== 'undefined' ? d.x0 : d.x),
maxAccessor: d => (typeof d.x1 !== 'undefined' ? d.x1 : d.x),
range: [0, innerWidth],
- ...xScale,
+ ...xScaleObject,
});
- result.yScale = getScaleForAccessor({
+ const yScale = getScaleForAccessor({
allData,
minAccessor: d => (typeof d.y0 !== 'undefined' ? d.y0 : d.y),
maxAccessor: d => (typeof d.y1 !== 'undefined' ? d.y1 : d.y),
range: [innerHeight, 0],
- ...yScale,
+ ...yScaleObject,
});
React.Children.forEach(children, (Child) => { // Child-specific scales or adjustments here
@@ -104,16 +113,20 @@ class XYChart extends React.PureComponent {
});
const offset = dummyBand.bandwidth() / 2;
- result.xScale.range([offset, innerWidth - offset]);
- result.xScale.barWidth = dummyBand.bandwidth();
- result.xScale.offset = offset;
+ xScale.range([offset, innerWidth - offset]);
+ xScale.barWidth = dummyBand.bandwidth();
+ xScale.offset = offset;
}
if (isCirclePackSeries(name)) {
- result.yScale.domain([-innerHeight / 2, innerHeight / 2]);
+ yScale.domain([-innerHeight / 2, innerHeight / 2]);
}
});
- return result;
+ return {
+ allData,
+ xScale,
+ yScale,
+ };
}
static getDimmensions(props) {
@@ -128,11 +141,10 @@ class XYChart extends React.PureComponent {
static getStateFromProps(props) {
const { margin, innerWidth, innerHeight } = XYChart.getDimmensions(props);
- const { allData, dataByIndex, xScale, yScale } = XYChart.collectScalesFromProps(props);
+ const { allData, xScale, yScale } = XYChart.collectScalesFromProps(props);
return {
allData,
- dataByIndex,
innerHeight,
innerWidth,
margin,
@@ -198,7 +210,6 @@ class XYChart extends React.PureComponent {
const {
allData,
- dataByIndex,
innerWidth,
innerHeight,
margin,
@@ -232,7 +243,7 @@ class XYChart extends React.PureComponent {
strokeWidth={theme.gridStyles && theme.gridStyles.strokeWidth}
/>}
- {React.Children.map(children, (Child, childIndex) => {
+ {React.Children.map(children, (Child) => {
const name = componentName(Child);
if (isAxis(name)) {
const styleKey = name[0].toLowerCase();
@@ -247,13 +258,13 @@ class XYChart extends React.PureComponent {
tickStyles: { ...theme[`${styleKey}TickStyles`], ...Child.props.tickStyles },
});
} else if (isSeries(name)) {
+ const { onMouseLeave: childMouseLeave, onMouseMove: childMouseMove } = Child.props;
return React.cloneElement(Child, {
- data: dataByIndex[childIndex],
xScale,
yScale,
barWidth,
- onMouseLeave: useVoronoi ? null : onMouseLeave,
- onMouseMove: useVoronoi ? null : onMouseMove,
+ onMouseLeave: typeof childMouseLeave !== 'undefined' ? childMouseLeave : onMouseLeave,
+ onMouseMove: typeof childMouseMove !== 'undefined' ? childMouseMove : onMouseMove,
});
} else if (isCrossHair(name)) {
CrossHair = Child;
@@ -266,7 +277,7 @@ class XYChart extends React.PureComponent {
{useVoronoi &&
isDefined(d.x) && isDefined(d.y))}
x={voronoiX}
y={voronoiY}
width={innerWidth}
diff --git a/packages/xy-chart/src/enhancer/WithTooltip.jsx b/packages/xy-chart/src/enhancer/WithTooltip.jsx
index b42cdc85..18296f62 100644
--- a/packages/xy-chart/src/enhancer/WithTooltip.jsx
+++ b/packages/xy-chart/src/enhancer/WithTooltip.jsx
@@ -1,13 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { localPoint } from '@vx/event';
-
-import {
- withTooltip,
- TooltipWithBounds,
- withTooltipPropTypes as vxTooltipPropTypes,
-} from '@vx/tooltip';
+import localPoint from '@vx/event/build/localPoint';
+import withTooltip from '@vx/tooltip/build/enhancers/withTooltip';
+import TooltipWithBounds, { withTooltipPropTypes as vxTooltipPropTypes } from '@vx/tooltip/build/tooltips/TooltipWithBounds';
export const withTooltipPropTypes = {
onMouseMove: PropTypes.func, // expects to be called like func({ event, datum })
diff --git a/packages/xy-chart/src/glyph/GlyphDotComponent.jsx b/packages/xy-chart/src/glyph/GlyphDotComponent.jsx
index fed85f4a..d96bfe58 100644
--- a/packages/xy-chart/src/glyph/GlyphDotComponent.jsx
+++ b/packages/xy-chart/src/glyph/GlyphDotComponent.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { GlyphDot } from '@vx/glyph';
+import GlyphDot from '@vx/glyph/build/glyphs/Dot';
import { pointComponentPropTypes } from '../series/PointSeries';
diff --git a/packages/xy-chart/src/index.js b/packages/xy-chart/src/index.js
index e889e5fa..73e1398e 100644
--- a/packages/xy-chart/src/index.js
+++ b/packages/xy-chart/src/index.js
@@ -16,7 +16,7 @@ export { default as CrossHair } from './chart/CrossHair';
export { default as WithTooltip, withTooltipPropTypes } from './enhancer/WithTooltip';
export { LinearGradient } from '@vx/gradient';
-export { PatternLines } from '@vx/pattern';
+export { PatternLines, PatternCircles, PatternWaves, PatternHexagons } from '@vx/pattern';
export { withScreenSize, withParentSize } from '@vx/responsive';
export { default as withTheme } from './enhancer/withTheme';
diff --git a/packages/xy-chart/src/series/AreaSeries.jsx b/packages/xy-chart/src/series/AreaSeries.jsx
index db2267b4..2d22eb4a 100644
--- a/packages/xy-chart/src/series/AreaSeries.jsx
+++ b/packages/xy-chart/src/series/AreaSeries.jsx
@@ -1,20 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { AreaClosed, LinePath } from '@vx/shape';
-import { Group } from '@vx/group';
-import { color } from '@data-ui/theme';
+import Area from '@vx/shape/build/shapes/Area';
+import Group from '@vx/group/build/Group';
+import LinePath from '@vx/shape/build/shapes/LinePath';
+import color from '@data-ui/theme/build/color';
import interpolatorLookup from '../utils/interpolatorLookup';
import { callOrValue, isDefined } from '../utils/chartUtils';
import findClosestDatum from '../utils/findClosestDatum';
-import { lineSeriesDataShape } from '../utils/propShapes';
+import { areaSeriesDataShape, interpolationShape } from '../utils/propShapes';
const propTypes = {
- data: lineSeriesDataShape.isRequired,
+ data: areaSeriesDataShape.isRequired,
fill: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
fillOpacity: PropTypes.oneOfType([PropTypes.func, PropTypes.number]),
- interpolation: PropTypes.oneOf(['linear', 'cardinal']), // @todo add more
+ interpolation: interpolationShape,
label: PropTypes.string.isRequired,
stroke: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
strokeDasharray: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
@@ -28,7 +29,7 @@ const propTypes = {
};
const defaultProps = {
- interpolation: 'cardinal',
+ interpolation: 'monotoneX',
stroke: color.default,
strokeWidth: 3,
strokeDasharray: null,
@@ -37,13 +38,16 @@ const defaultProps = {
fillOpacity: 0.3,
xScale: null,
yScale: null,
- onMouseMove: null,
- onMouseLeave: null,
+ onMouseMove: undefined,
+ onMouseLeave: undefined,
};
const x = d => d.x;
-const y = d => d.y;
-const defined = d => isDefined(y(d));
+const getY = d => d.y;
+const getY0 = d => d.y0;
+const getY1 = d => d.y1;
+const definedClosed = d => isDefined(getY(d));
+const definedOpen = d => isDefined(getY0(d)) && isDefined(getY1(d));
export default class AreaSeries extends React.PureComponent {
render() {
@@ -62,24 +66,32 @@ export default class AreaSeries extends React.PureComponent {
onMouseMove,
onMouseLeave,
} = this.props;
-
if (!xScale || !yScale) return null;
+ const datum0 = data[0] || {};
+ const isClosed = !definedOpen(datum0);
+ const yMin = yScale.domain()[0];
+ const y0 = isClosed ? () => yMin : getY0;
+ const y1 = isClosed ? getY : getY1;
+ const defined = isClosed ? definedClosed : definedOpen;
+ const strokeDasharrayValue = callOrValue(strokeDasharray, data);
+ const strokeValue = callOrValue(stroke, data);
const strokeWidthValue = callOrValue(strokeWidth, data);
const fillValue = callOrValue(fill, data);
- const curve = interpolatorLookup[interpolation] || interpolatorLookup.cardinal;
+ const curve = interpolatorLookup[interpolation] || interpolatorLookup.monotoneX;
return (
{
const d = findClosestDatum({ data, getX: x, event, xScale });
onMouseMove({ event, data, datum: d, color: fillValue });
})}
onMouseLeave={onMouseLeave}
>
-
+ {/* only draw a stroke for the top and bottom */}
+ {strokeWidthValue > 0 && !isClosed &&
+ }
{strokeWidthValue > 0 &&
d.x;
diff --git a/packages/xy-chart/src/series/GroupedBarSeries.jsx b/packages/xy-chart/src/series/GroupedBarSeries.jsx
index 0a3d6aa5..5a300fe4 100644
--- a/packages/xy-chart/src/series/GroupedBarSeries.jsx
+++ b/packages/xy-chart/src/series/GroupedBarSeries.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { BarGroup } from '@vx/shape';
-import { color } from '@data-ui/theme';
+import BarGroup from '@vx/shape/build/shapes/BarGroup';
+import color from '@data-ui/theme/build/color';
import { groupedBarSeriesDataShape } from '../utils/propShapes';
import { scaleTypeToScale } from '../utils/chartUtils';
@@ -30,8 +30,8 @@ const defaultProps = {
strokeWidth: 1,
xScale: null,
yScale: null,
- onMouseMove: null,
- onMouseLeave: null,
+ onMouseMove: undefined,
+ onMouseLeave: undefined,
};
const x = d => d.x;
diff --git a/packages/xy-chart/src/series/IntervalSeries.jsx b/packages/xy-chart/src/series/IntervalSeries.jsx
index 7106eee8..94c389f3 100644
--- a/packages/xy-chart/src/series/IntervalSeries.jsx
+++ b/packages/xy-chart/src/series/IntervalSeries.jsx
@@ -1,8 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Group } from '@vx/group';
-import { Bar } from '@vx/shape';
-import { color } from '@data-ui/theme';
+
+import Group from '@vx/group/build/Group';
+import Bar from '@vx/shape/build/shapes/Bar';
+import color from '@data-ui/theme/build/color';
import { intervalSeriesDataShape } from '../utils/propShapes';
import { callOrValue } from '../utils/chartUtils';
@@ -29,8 +30,8 @@ const defaultProps = {
strokeWidth: 1,
xScale: null,
yScale: null,
- onMouseMove: null,
- onMouseLeave: null,
+ onMouseMove: undefined,
+ onMouseLeave: undefined,
};
const x0 = d => d.x0;
diff --git a/packages/xy-chart/src/series/LineSeries.jsx b/packages/xy-chart/src/series/LineSeries.jsx
index f81fae5b..c6bef6cc 100644
--- a/packages/xy-chart/src/series/LineSeries.jsx
+++ b/packages/xy-chart/src/series/LineSeries.jsx
@@ -1,18 +1,18 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { curveCardinal, curveLinear } from '@vx/curve';
-import { GlyphDot } from '@vx/glyph';
-import { LinePath } from '@vx/shape';
-import { color } from '@data-ui/theme';
+import GlyphDot from '@vx/glyph/build/glyphs/Dot';
+import LinePath from '@vx/shape/build/shapes/LinePath';
+import color from '@data-ui/theme/build/color';
import { callOrValue, isDefined } from '../utils/chartUtils';
import findClosestDatum from '../utils/findClosestDatum';
-import { lineSeriesDataShape } from '../utils/propShapes';
+import interpolatorLookup from '../utils/interpolatorLookup';
+import { interpolationShape, lineSeriesDataShape } from '../utils/propShapes';
const propTypes = {
data: lineSeriesDataShape.isRequired,
- interpolation: PropTypes.oneOf(['linear', 'cardinal']), // @todo add more
+ interpolation: interpolationShape,
label: PropTypes.string.isRequired,
showPoints: PropTypes.bool,
@@ -29,7 +29,7 @@ const propTypes = {
};
const defaultProps = {
- interpolation: 'cardinal',
+ interpolation: 'monotoneX',
showPoints: false,
stroke: color.default,
strokeDasharray: null,
@@ -37,8 +37,8 @@ const defaultProps = {
strokeLinecap: 'round',
xScale: null,
yScale: null,
- onMouseMove: null,
- onMouseLeave: null,
+ onMouseMove: undefined,
+ onMouseLeave: undefined,
};
const x = d => d.x;
@@ -63,6 +63,7 @@ export default class LineSeries extends React.PureComponent {
} = this.props;
if (!xScale || !yScale) return null;
const strokeValue = callOrValue(stroke);
+ const curve = interpolatorLookup[interpolation] || interpolatorLookup.monotoneX;
return (
(event) => {
const d = findClosestDatum({ data, getX: x, event, xScale });
diff --git a/packages/xy-chart/src/series/PointSeries.jsx b/packages/xy-chart/src/series/PointSeries.jsx
index b070371b..d010fa51 100644
--- a/packages/xy-chart/src/series/PointSeries.jsx
+++ b/packages/xy-chart/src/series/PointSeries.jsx
@@ -1,7 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Group } from '@vx/group';
-import { chartTheme, color } from '@data-ui/theme';
+import Group from '@vx/group/build/Group';
+
+import chartTheme from '@data-ui/theme/build/chartTheme';
+import color from '@data-ui/theme/build/color';
import { callOrValue, isDefined } from '../utils/chartUtils';
import { pointSeriesDataShape } from '../utils/propShapes';
@@ -53,8 +55,8 @@ export const defaultProps = {
strokeWidth: 1,
xScale: null,
yScale: null,
- onMouseMove: null,
- onMouseLeave: null,
+ onMouseMove: undefined,
+ onMouseLeave: undefined,
};
export default class PointSeries extends React.PureComponent {
diff --git a/packages/xy-chart/src/series/StackedBarSeries.jsx b/packages/xy-chart/src/series/StackedBarSeries.jsx
index 3e13d109..f0f28777 100644
--- a/packages/xy-chart/src/series/StackedBarSeries.jsx
+++ b/packages/xy-chart/src/series/StackedBarSeries.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { BarStack } from '@vx/shape';
-import { color } from '@data-ui/theme';
+import BarStack from '@vx/shape/build/shapes/BarStack';
+import color from '@data-ui/theme/build/color';
import { stackedBarSeriesDataShape } from '../utils/propShapes';
import { scaleTypeToScale } from '../utils/chartUtils';
@@ -27,8 +27,8 @@ const defaultProps = {
strokeWidth: 1,
xScale: null,
yScale: null,
- onMouseMove: null,
- onMouseLeave: null,
+ onMouseMove: undefined,
+ onMouseLeave: undefined,
};
const x = d => d.x;
diff --git a/packages/xy-chart/src/utils/findClosestDatum.js b/packages/xy-chart/src/utils/findClosestDatum.js
index 54b0d8c5..1e71dde8 100644
--- a/packages/xy-chart/src/utils/findClosestDatum.js
+++ b/packages/xy-chart/src/utils/findClosestDatum.js
@@ -3,14 +3,14 @@ import { localPoint } from '@vx/event';
export default function findClosestDatum({ data, getX, xScale, event }) {
if (!event || !event.target || !event.target.ownerSVGElement) return null;
- const bisect = bisector(getX).right;
+ const bisect = bisector(getX).left;
// if the g element has a transform we need to be in g coords not svg coords
const gElement = event.target.ownerSVGElement.firstChild;
const { x } = localPoint(gElement, event);
const dataX = xScale.invert(x);
const index = bisect(data, dataX, 1);
const d0 = data[index - 1];
- const d1 = data[index];
+ const d1 = data[index] || {};
const d = !d0 || (Math.abs(dataX - getX(d0)) > Math.abs(dataX - getX(d1))) ? d1 : d0;
return d;
}
diff --git a/packages/xy-chart/src/utils/interpolatorLookup.js b/packages/xy-chart/src/utils/interpolatorLookup.js
index 2971ee72..0bfe19cd 100644
--- a/packages/xy-chart/src/utils/interpolatorLookup.js
+++ b/packages/xy-chart/src/utils/interpolatorLookup.js
@@ -1,6 +1,15 @@
-import { curveCardinal, curveLinear } from '@vx/curve';
+import {
+ curveCardinal,
+ curveLinear,
+ curveMonotoneX,
+ curveMonotoneY,
+ curveNatural,
+} from '@vx/curve';
export default {
linear: curveLinear,
cardinal: curveCardinal,
+ monotoneX: curveMonotoneX,
+ monotoneY: curveMonotoneY,
+ natural: curveNatural,
};
diff --git a/packages/xy-chart/src/utils/propShapes.js b/packages/xy-chart/src/utils/propShapes.js
index 0da9d49f..81024621 100644
--- a/packages/xy-chart/src/utils/propShapes.js
+++ b/packages/xy-chart/src/utils/propShapes.js
@@ -1,4 +1,5 @@
import PropTypes from 'prop-types';
+import interpolatorLookup from './interpolatorLookup';
export const scaleShape = PropTypes.shape({
type: PropTypes.oneOf([
@@ -28,6 +29,20 @@ export const lineSeriesDataShape = PropTypes.arrayOf(
}),
);
+export const areaSeriesDataShape = PropTypes.arrayOf(
+ PropTypes.shape({
+ x: PropTypes.oneOfType([ // data with null x/y are not rendered
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.instanceOf(Date),
+ PropTypes.object, // eg a moment() instance
+ ]),
+ y: PropTypes.number, // null data are not rendered
+ y0: PropTypes.number,
+ y1: PropTypes.number,
+ }),
+);
+
export const barSeriesDataShape = PropTypes.arrayOf(PropTypes.shape({
x: PropTypes.oneOfType([
PropTypes.string,
@@ -124,3 +139,5 @@ export const themeShape = PropTypes.shape({
yAxisStyles: axisStylesShape,
yTickStyles: tickStylesShape,
});
+
+export const interpolationShape = PropTypes.oneOf(Object.keys(interpolatorLookup));
diff --git a/packages/xy-chart/test/AreaSeries.test.js b/packages/xy-chart/test/AreaSeries.test.js
index faa52534..7146c1aa 100644
--- a/packages/xy-chart/test/AreaSeries.test.js
+++ b/packages/xy-chart/test/AreaSeries.test.js
@@ -1,6 +1,7 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
-import { AreaClosed, LinePath } from '@vx/shape';
+import Area from '@vx/shape/build/shapes/Area';
+import LinePath from '@vx/shape/build/shapes/LinePath';
import { XYChart, AreaSeries } from '../src/';
@@ -28,7 +29,7 @@ describe('', () => {
expect(shallow().type()).toBeNull();
});
- test('it should render an AreaClosed for each AreaSeries', () => {
+ test('it should render an Area for each AreaSeries', () => {
const wrapper = shallow(
({ ...d, x: d.date, y: d.num }))} />
@@ -36,7 +37,7 @@ describe('', () => {
,
);
expect(wrapper.find(AreaSeries).length).toBe(2);
- expect(wrapper.find(AreaSeries).first().dive().find(AreaClosed).length).toBe(1);
+ expect(wrapper.find(AreaSeries).first().dive().find(Area).length).toBe(1);
});
test('it should render a LinePath if strokeWidth is non-zero', () => {
@@ -71,7 +72,7 @@ describe('', () => {
);
// event listener is on area's parent, but .parent().simulate() call throws in enzyme 3
- const area = wrapper.find(AreaClosed);
+ const area = wrapper.find(Area);
area.simulate('mousemove');
expect(onMouseMove).toHaveBeenCalledTimes(1);
diff --git a/packages/xy-chart/test/BarSeries.test.js b/packages/xy-chart/test/BarSeries.test.js
index d971a0e1..cb893963 100644
--- a/packages/xy-chart/test/BarSeries.test.js
+++ b/packages/xy-chart/test/BarSeries.test.js
@@ -1,4 +1,4 @@
-import { Bar } from '@vx/shape';
+import Bar from '@vx/shape/build/shapes/Bar';
import React from 'react';
import { shallow, mount } from 'enzyme';
import { XYChart, BarSeries } from '../src/';
diff --git a/packages/xy-chart/test/CrossHair.test.js b/packages/xy-chart/test/CrossHair.test.js
index 0c894cfb..2414a56a 100644
--- a/packages/xy-chart/test/CrossHair.test.js
+++ b/packages/xy-chart/test/CrossHair.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { shallow } from 'enzyme';
-import { Line } from '@vx/shape';
+import Line from '@vx/shape/build/shapes/Line';
import CrossHair from '../src/chart/CrossHair';
diff --git a/packages/xy-chart/test/GroupedBarSeries.test.js b/packages/xy-chart/test/GroupedBarSeries.test.js
index 639216d2..14d9c9ec 100644
--- a/packages/xy-chart/test/GroupedBarSeries.test.js
+++ b/packages/xy-chart/test/GroupedBarSeries.test.js
@@ -1,4 +1,5 @@
-import { BarGroup, Bar } from '@vx/shape';
+import Bar from '@vx/shape/build/shapes/Bar';
+import BarGroup from '@vx/shape/build/shapes/BarGroup';
import React from 'react';
import { shallow, mount } from 'enzyme';
import { XYChart, GroupedBarSeries } from '../src/';
diff --git a/packages/xy-chart/test/HorizontalReferenceLine.test.js b/packages/xy-chart/test/HorizontalReferenceLine.test.js
index f428b8ed..0945ee55 100644
--- a/packages/xy-chart/test/HorizontalReferenceLine.test.js
+++ b/packages/xy-chart/test/HorizontalReferenceLine.test.js
@@ -59,4 +59,41 @@ describe('', () => {
expect(line.prop('from').y).toBe(scaledValue);
expect(line.prop('to').y).toBe(scaledValue);
});
+
+ test('it should render a label if specified', () => {
+ const label = 'label!';
+
+ const noLabelWrapper = shallow(
+
+
+ ,
+ ).find(HorizontalReferenceLine).dive();
+
+ const withLabelWrapper = shallow(
+
+
+ ,
+ ).find(HorizontalReferenceLine).dive();
+
+ expect(noLabelWrapper.find('text').length).toBe(0);
+ expect(withLabelWrapper.find('text').length).toBe(1);
+ expect(withLabelWrapper.find('text').text()).toBe(label);
+ });
+
+ test('it should use labelProps if passed', () => {
+ const wrapper = shallow(
+
+
+ ,
+ ).find(HorizontalReferenceLine).dive();
+
+ const text = wrapper.find('text');
+ expect(text.prop('id')).toBe('test');
+ });
});
diff --git a/packages/xy-chart/test/IntervalSeries.test.js b/packages/xy-chart/test/IntervalSeries.test.js
index e86aa78e..b5df4c2d 100644
--- a/packages/xy-chart/test/IntervalSeries.test.js
+++ b/packages/xy-chart/test/IntervalSeries.test.js
@@ -1,4 +1,4 @@
-import { Bar } from '@vx/shape';
+import Bar from '@vx/shape/build/shapes/Bar';
import React from 'react';
import { shallow, mount } from 'enzyme';
diff --git a/packages/xy-chart/test/LineSeries.test.js b/packages/xy-chart/test/LineSeries.test.js
index d6528d7a..e400c37d 100644
--- a/packages/xy-chart/test/LineSeries.test.js
+++ b/packages/xy-chart/test/LineSeries.test.js
@@ -1,7 +1,7 @@
-import { GlyphDot } from '@vx/glyph';
+import GlyphDot from '@vx/glyph/build/glyphs/Dot';
+import LinePath from '@vx/shape/build/shapes/LinePath';
import React from 'react';
import { shallow, mount } from 'enzyme';
-import { LinePath } from '@vx/shape';
import { XYChart, LineSeries } from '../src/';
diff --git a/packages/xy-chart/test/StackedBarSeries.test.js b/packages/xy-chart/test/StackedBarSeries.test.js
index 6233546b..d705ed3e 100644
--- a/packages/xy-chart/test/StackedBarSeries.test.js
+++ b/packages/xy-chart/test/StackedBarSeries.test.js
@@ -1,4 +1,5 @@
-import { Bar, BarStack } from '@vx/shape';
+import Bar from '@vx/shape/build/shapes/Bar';
+import BarStack from '@vx/shape/build/shapes/BarStack';
import React from 'react';
import { shallow, mount } from 'enzyme';
import { XYChart, StackedBarSeries } from '../src/';
diff --git a/packages/xy-chart/test/Voronoi.test.js b/packages/xy-chart/test/Voronoi.test.js
index 186c8c62..6c837c4c 100644
--- a/packages/xy-chart/test/Voronoi.test.js
+++ b/packages/xy-chart/test/Voronoi.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
-import { VoronoiPolygon } from '@vx/voronoi';
+import VoronoiPolygon from '@vx/voronoi/build/components/VoronoiPolygon';
import Voronoi from '../src/chart/Voronoi';
diff --git a/packages/xy-chart/test/XAxis.test.js b/packages/xy-chart/test/XAxis.test.js
index 85a83c45..ee5708e2 100644
--- a/packages/xy-chart/test/XAxis.test.js
+++ b/packages/xy-chart/test/XAxis.test.js
@@ -1,6 +1,7 @@
import React from 'react';
import { shallow } from 'enzyme';
-import { AxisBottom, AxisTop } from '@vx/axis';
+import AxisBottom from '@vx/axis/build/axis/AxisBottom';
+import AxisTop from '@vx/axis/build/axis/AxisTop';
import { XYChart, XAxis, LineSeries } from '../src/';
describe('', () => {
diff --git a/packages/xy-chart/test/XYChart.test.js b/packages/xy-chart/test/XYChart.test.js
index 11ae796c..f5e509a7 100644
--- a/packages/xy-chart/test/XYChart.test.js
+++ b/packages/xy-chart/test/XYChart.test.js
@@ -1,5 +1,5 @@
-import { Grid } from '@vx/grid';
-import { Group } from '@vx/group';
+import Grid from '@vx/grid/build/grids/Grid';
+import Group from '@vx/group/build/Group';
import React from 'react';
import { shallow } from 'enzyme';
diff --git a/packages/xy-chart/test/YAxis.test.js b/packages/xy-chart/test/YAxis.test.js
index 0a6a7606..a1561278 100644
--- a/packages/xy-chart/test/YAxis.test.js
+++ b/packages/xy-chart/test/YAxis.test.js
@@ -1,6 +1,7 @@
import React from 'react';
import { shallow } from 'enzyme';
-import { AxisLeft, AxisRight } from '@vx/axis';
+import AxisLeft from '@vx/axis/build/axis/AxisLeft';
+import AxisRight from '@vx/axis/build/axis/AxisRight';
import { XYChart, YAxis, LineSeries } from '../src/';
describe('', () => {
diff --git a/packages/xy-chart/test/computeCirclePack.test.js b/packages/xy-chart/test/computeCirclePack.test.js
index b4a6be3b..39306dd7 100644
--- a/packages/xy-chart/test/computeCirclePack.test.js
+++ b/packages/xy-chart/test/computeCirclePack.test.js
@@ -1,4 +1,4 @@
-import { scaleLinear } from '@vx/scale';
+import scaleLinear from '@vx/scale/build/scales/linear';
import computeCirclePack from '../src/utils/computeCirclePack';
describe('computeCirclePack', () => {