Skip to content

Commit

Permalink
feat(stack): add StackDots component
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphael Benitte committed May 8, 2016
1 parent 3426e4d commit fa879a0
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- Stack
- [`<Stack />`](https://plouc.github.io/nivo/#/stack)
- [`<ResponsiveStack />`](https://plouc.github.io/nivo/#/stack)
- [`<StackDots />`](https://plouc.github.io/nivo/#/stack)
- TreeMap
- [`<TreeMapD3 />`](https://plouc.github.io/nivo/#/treemap/d3)
- [`<ResponsiveTreeMapD3 />`](https://plouc.github.io/nivo/#/treemap/d3)
Expand Down
21 changes: 18 additions & 3 deletions src/components/charts/stack/Stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Nivo from '../../../Nivo';
import { lineInterpolation } from '../../../PropTypes';
import { getColorRange } from '../../../ColorUtils';
import { margin as marginPropType } from '../../../PropTypes';
import decoratorsFromReactChildren from '../../../lib/decoratorsFromReactChildren';


class Stack extends Component {
Expand Down Expand Up @@ -78,19 +79,33 @@ class Stack extends Component {
.attr('d', area)
.style('fill', (d, i) => color(i))
;

const stackContext = {
element: wrapper,
width, height,
stacked,
xScale, yScale,
color,
transitionDuration, transitionEasing
};

this.decorators.forEach(decorator => {
decorator(stackContext);
});
}

shouldComponentUpdate(nextProps) {
this.decorators = decoratorsFromReactChildren(nextProps.children, 'decorateStack');

this.renderD3(nextProps);

return false;
}

componentDidMount() {
this.renderD3(this.props);
}
this.decorators = decoratorsFromReactChildren(this.props.children, 'decorateStack');

componentWillMount() {
this.renderD3(this.props);
}

render() {
Expand Down
146 changes: 146 additions & 0 deletions src/components/charts/stack/StackDots.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* This file is part of the nivo library.
*
* (c) Raphaël Benitte
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
'use strict';

import React, { Component, PropTypes } from 'react';
import invariant from 'invariant';
import d3 from 'd3';
import { getColorGenerator } from '../../../ColorUtils';


class StackDots extends Component {
static decorateStack(element) {
const { props } = element;

const colorFn = getColorGenerator(props.color);
const borderColorFn = getColorGenerator(props.borderColor);
const { showOnOver } = props;

// Receive context from Parent Stack component
return ({
element,
stacked,
width, height,
xScale, yScale,
color,
transitionDuration, transitionEasing
}) => {
const slices = [];
stacked.forEach(layer => {
layer.forEach((datum, i) => {
if (!slices[i]) {
slices[i] = [];
}

slices[i].push(datum);
});
});

const elements = element.selectAll('.nivo_stack_slices').data(slices);

const newSlices = elements.enter().append('g')
.attr('class', 'nivo_stack_slices')
.attr('transform', (d, i) => `translate(${xScale(i)},0)`)
.style('opacity', showOnOver ? 0 : 1)
.style('cursor', 'pointer')
.style('pointer-events', 'all')
;

newSlices.append('rect')
.attr('width', props.radius * 2 + 20)
.attr('height', height)
.attr('transform', `translate(-${props.radius + 10},0)`)
.style('fill', 'none')
.style('pointer-events', 'all')
;

newSlices.selectAll('circle').data(d => d).enter().append('circle')
.attr('r', props.radius)
.attr('transform', d => {
return `translate(0,${yScale(d.y0 + d.y)})`;
})
.style('fill', (d, i) => colorFn({ color: color(i) }))
.style('stroke-width', props.borderWidth)
.style('stroke', (d, i) => borderColorFn({ color: color(i) }))
;

elements
.style('opacity', showOnOver ? 0 : 1)
.on('mouseover', function () {
if (!showOnOver) {
return;
}

d3.select(this)
.transition()
.duration(100)
.style('opacity', 1)
;
})
.on('mouseout', function () {
if (!showOnOver) {
return;
}

d3.select(this)
.transition()
.duration(100)
.style('opacity', 0)
;
})
.transition()
.duration(transitionDuration)
.ease(transitionEasing)
.attr('transform', (d, i) => `translate(${xScale(i)},0)`)
;

elements
.selectAll('circle').data(d => d)
.transition()
.duration(transitionDuration)
.ease(transitionEasing)
.attr('r', props.radius)
.attr('transform', d => {
return `translate(0,${yScale(d.y0 + d.y)})`;
})
.style('fill', (d, i) => colorFn({ color: color(i) }))
.style('stroke-width', props.borderWidth)
.style('stroke', (d, i) => borderColorFn({ color: color(i) }))
;
};
}

render() {
invariant(
false,
'<StackDots> element is for Stack configuration only and should not be rendered'
);
}
}

const { number, bool, any } = PropTypes;

StackDots.propTypes = {
showOnOver: bool.isRequired,
radius: number.isRequired,
color: any.isRequired,
borderWidth: number.isRequired,
borderColor: any.isRequired,
};

StackDots.defaultProps = {
showOnOver: false,
radius: 4,
color: 'inherit',
borderWidth: 1,
borderColor: 'inherit:darker(.4)',
};


export default StackDots;
1 change: 1 addition & 0 deletions src/components/charts/stack/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@

export Stack from './Stack';
export ResponsiveStack from './ResponsiveStack';
export StackDots from './StackDots';
66 changes: 66 additions & 0 deletions src/lib/charts/stack/StackD3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* This file is part of the nivo library.
*
* (c) Raphaël Benitte
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
'use strict';

import { flatten } from '../../../DataUtils';


/**
* This wrapper is responsible for computing stack chart positions.
* It's used for all Stack related chart components.
*
* @returns {{ compute: (function) }}
* @constructor
*/
const StackD3 = () => {
const layout = d3.layout.pack();

return {
/**
*
* @param {number} width
* @param {number} height
* @param {object} data
* @param {string} identityProperty
* @param {function} valueAccessor
* @param {number} padding
* @param {function} color
* @returns {array}
*/
compute({
width, height,
data,
identityProperty, valueAccessor,
padding,
color
}) {
layout
.value(valueAccessor)
.sort(null)
.size([width, height])
.padding(padding)
;

const flattened = flatten(data, identityProperty);
const nodes = layout.nodes(flattened)
.filter(d => !d.children)
.map(d => {
d.color = color(d.parentId);

return d;
})
;

return nodes;
}
}
};


export default StackD3;

0 comments on commit fa879a0

Please sign in to comment.