Skip to content

Commit

Permalink
feat(scales): improve time scale support
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Benitte authored and Raphaël Benitte committed Aug 30, 2018
1 parent 84aa832 commit 614038e
Show file tree
Hide file tree
Showing 18 changed files with 426 additions and 279 deletions.
86 changes: 37 additions & 49 deletions packages/line/src/Line.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import {
Axes,
Grid,
} from '@nivo/core'
import { prepareSeries } from '@nivo/scales'
import { computeXYScalesForSeries } from '@nivo/scales'
import { BoxLegendSvg } from '@nivo/legends'
import { computeScales, generateLines } from './compute'
import { generateLines } from './compute'
import LineAreas from './LineAreas'
import LineLines from './LineLines'
import LineSlices from './LineSlices'
Expand All @@ -39,8 +39,7 @@ const Line = ({
lines,
lineGenerator,
areaGenerator,
xScale,
yScale,
xy,
slices,

// dimensions
Expand Down Expand Up @@ -111,8 +110,8 @@ const Line = ({
theme={theme}
width={width}
height={height}
xScale={enableGridX ? xScale : null}
yScale={enableGridY ? yScale : null}
xScale={enableGridX ? xy.x.scale : null}
yScale={enableGridY ? xy.y.scale : null}
xValues={gridXValues}
yValues={gridYValues}
{...motionProps}
Expand All @@ -121,13 +120,13 @@ const Line = ({
markers={markers}
width={width}
height={height}
xScale={xScale}
yScale={yScale}
xScale={xy.x.scale}
yScale={xy.y.scale}
theme={theme}
/>
<Axes
xScale={xScale}
yScale={yScale}
xScale={xy.x.scale}
yScale={xy.y.scale}
width={width}
height={height}
theme={theme}
Expand Down Expand Up @@ -224,51 +223,40 @@ const enhance = compose(
.y(d => d.y)
.curve(curveFromProp(curve)),
})),
withPropsOnChange(['data'], ({ data }) => ({
enhancedData: prepareSeries(data),
})),
withPropsOnChange(
['enhancedData', 'width', 'height', 'xScale', 'yScale'],
({ enhancedData, width, height, xScale, yScale }) =>
computeScales({
data: enhancedData,
width,
height,
xScale,
yScale,
})
['data', 'xScale', 'yScale', 'width', 'height'],
({ data, xScale, yScale, width, height }) => ({
xy: computeXYScalesForSeries(data, xScale, yScale, width, height),
})
),
withPropsOnChange(
['getColor', 'xScale', 'yScale', 'enhancedData'],
({ xScale, yScale, getColor, enhancedData }) => {
const lines = generateLines(enhancedData, xScale, yScale, getColor)
withPropsOnChange(['getColor', 'xy'], ({ getColor, xy }) => {
const lines = generateLines(xy, getColor)

const slices = enhancedData.x.sorted.map(x => {
let points = []
lines.forEach(line => {
const datum = line.data.find(datum => datum.data.x === x)
if (datum !== undefined && datum.x !== null && datum.y !== null) {
points.push({
id: line.id,
x,
y: datum.y,
color: line.color,
data: datum.data,
})
}
})
points = sortBy(points, 'y')

return {
id: x,
x: xScale(x),
points,
const slices = xy.x.sorted.map(x => {
let points = []
lines.forEach(line => {
const datum = line.data.find(datum => datum.data.x === x)
if (datum !== undefined && datum.x !== null && datum.y !== null) {
points.push({
id: line.id,
x,
y: datum.y,
color: line.color,
data: datum.data,
})
}
})
points = sortBy(points, 'y')

return { lines, slices }
}
),
return {
id: x,
x: xy.x.scale(x),
points,
}
})

return { lines, slices }
}),
pure
)

Expand Down
12 changes: 10 additions & 2 deletions packages/line/src/LineLines.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,16 @@ LineLines.propTypes = {
x: PropTypes.number,
y: PropTypes.number,
data: PropTypes.shape({
x: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
y: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
x: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Date),
]),
y: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Date),
]),
}).isRequired,
})
).isRequired,
Expand Down
6 changes: 5 additions & 1 deletion packages/line/src/LineSlices.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ const LineSlices = ({
LineSlices.propTypes = {
slices: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
id: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.instanceOf(Date),
]).isRequired,
x: PropTypes.number.isRequired,
points: PropTypes.arrayOf(
PropTypes.shape({
Expand Down
52 changes: 8 additions & 44 deletions packages/line/src/compute.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,26 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { linearScale, pointScale, timeScale } from '@nivo/scales'

export const computeScale = (scaleSpec, dimensions, data) => {
if (scaleSpec.type === 'linear') {
return linearScale(scaleSpec, dimensions, data)
} else if (scaleSpec.type === 'point') {
return pointScale(scaleSpec, dimensions, data)
} else if (scaleSpec.type === 'time') {
return timeScale(scaleSpec, dimensions, data)
}
}

export const computeScales = ({ data, width, height, xScale, yScale }) => ({
xScale: computeScale(
{
...xScale,
axis: 'x',
},
{
width,
height,
},
data
),
yScale: computeScale(
{
...yScale,
axis: 'y',
},
{
width,
height,
},
data
),
})

export const generateLines = (enhancedData, xScale, yScale, getColor) => {
if (yScale.stacked === true) {
return enhancedData.y.stack.series.map(serie => ({
export const generateLines = (xy, getColor) => {
if (xy.y.scale.stacked === true) {
return xy.y.stacked.series.map(serie => ({
...serie,
color: getColor(serie),
data: serie.data.map(datum => ({
x: datum.x !== null ? xScale(datum.x) : null,
y: datum.y !== null ? yScale(datum.y) : null,
x: datum.x !== null ? xy.x.scale(datum.x) : null,
y: datum.y !== null ? xy.y.scale(datum.y) : null,
data: datum,
})),
}))
}

return enhancedData.series.map(serie => ({
return xy.series.map(serie => ({
...serie,
color: getColor(serie),
data: serie.data.map(datum => ({
x: datum.x !== null ? xScale(datum.x) : null,
y: datum.y !== null ? yScale(datum.y) : null,
x: datum.x !== null ? xy.x.scale(datum.x) : null,
y: datum.y !== null ? xy.y.scale(datum.y) : null,
data: datum,
})),
}))
Expand Down
15 changes: 5 additions & 10 deletions packages/line/src/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
import PropTypes from 'prop-types'
import { lineCurvePropType } from '@nivo/core'
import { scalePropType } from '@nivo/scales'
import { LegendPropShape } from '@nivo/legends'

export const LinePropTypes = {
Expand All @@ -23,22 +24,18 @@ export const LinePropTypes = {
})
).isRequired,

xScale: PropTypes.func.isRequired, // computed
yScale: PropTypes.func.isRequired, // computed
xScale: scalePropType.isRequired,
yScale: scalePropType.isRequired,

xy: PropTypes.object.isRequired,

stacked: PropTypes.bool.isRequired,
curve: lineCurvePropType.isRequired,
areaGenerator: PropTypes.func.isRequired,
lineGenerator: PropTypes.func.isRequired,

lines: PropTypes.array.isRequired,
slices: PropTypes.array.isRequired,

minY: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.oneOf(['auto'])])
.isRequired,
maxY: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.oneOf(['auto'])])
.isRequired,

// axes & grid
axisTop: PropTypes.object,
axisRight: PropTypes.object,
Expand Down Expand Up @@ -99,8 +96,6 @@ export const LineDefaultProps = {
min: 0,
max: 'auto',
},
minY: 0,
maxY: 'auto',

// axes & grid
axisBottom: {},
Expand Down
43 changes: 31 additions & 12 deletions packages/line/stories/line.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const commonProperties = {
animate: true,
}

const curveOptions = ['linear', 'monotoneX']
const curveOptions = ['linear', 'monotoneX', 'step', 'stepBefore', 'stepAfter']

const CustomSymbol = ({ size, color, borderWidth, borderColor }) => (
<g>
Expand Down Expand Up @@ -59,7 +59,11 @@ stories.add(
'linear x scale',
withInfo(`
By default, \`xScale\` is a point scale, but you can switch to linear using
the \`xScale.type\` property.
the \`xScale.type\` property. It supports irregular intervals while \`point\`
scale doesn't.
If you want missing datums to appear as holes instead of connecting defined ones,
you should set their y value to \`null\`.
`)(() => (
<Line
{...commonProperties}
Expand Down Expand Up @@ -88,12 +92,10 @@ stories.add(
)

stories.add(
'time series',
'time x scale',
withInfo()(() => (
<Line
{...commonProperties}
curve="monotoneX"
height={700}
data={[
{
id: 'fake corp. A',
Expand All @@ -102,26 +104,43 @@ stories.add(
{ x: '2018-01-02', y: 5 },
{ x: '2018-01-03', y: 11 },
{ x: '2018-01-04', y: 9 },
{ x: '2018-01-05', y: 13 },
{ x: '2018-01-05', y: 12 },
{ x: '2018-01-06', y: 16 },
{ x: '2018-01-07', y: 12 },
{ x: '2018-01-07', y: 13 },
{ x: '2018-01-08', y: 13 },
],
},
{
id: 'fake corp. B',
data: [
{ x: '2018-01-04', y: 14 },
{ x: '2018-01-05', y: 14 },
{ x: '2018-01-06', y: 15 },
{ x: '2018-01-07', y: 11 },
{ x: '2018-01-08', y: 10 },
{ x: '2018-01-09', y: 12 },
{ x: '2018-01-10', y: 9 },
{ x: '2018-01-11', y: 7 },
],
},
]}
xScale={{
type: 'time',
format: '%Y-%m-%d',
}}
yScale={{
type: 'linear',
stacked: boolean('stacked', true),
}}
margin={{
bottom: 400,
left: 100,
stacked: boolean('stacked', false),
}}
axisBottom={{
format: '%m/%d',
}}
curve={select('curve', curveOptions, 'step')}
enableDotLabel={true}
dotSymbol={CustomSymbol}
dotSize={16}
dotBorderWidth={1}
dotBorderColor="inherit:darker(0.3)"
/>
))
)
Expand Down
2 changes: 1 addition & 1 deletion packages/sankey/src/Sankey.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import SankeyLinks from './SankeyLinks'
import SankeyLabels from './SankeyLabels'
import { SankeyPropTypes, sankeyAlignmentFromProp } from './props'
import enhance from './enhance'
import enhancedLine from '../../line/src/Line'

const getId = d => d.id

Expand Down Expand Up @@ -218,6 +217,7 @@ const Sankey = ({
}

Sankey.propTypes = SankeyPropTypes

const enhancedSankey = enhance(Sankey)
enhancedSankey.displayName = 'Sankey'

Expand Down
1 change: 1 addition & 0 deletions packages/scales/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
],
"dependencies": {
"d3-scale": "^2.1.2",
"d3-time-format": "^2.1.3",
"lodash": "^4.17.4"
},
"peerDependencies": {
Expand Down
Loading

0 comments on commit 614038e

Please sign in to comment.