bevspot-react-nvd3
Version:
React nvd3 reusable graph components.
147 lines (128 loc) • 4.54 kB
JavaScript
import React from 'react';
import d3 from 'd3';
import nv from 'bevspot-nvd3';
import {pick, without} from './utils.js'
let SETTINGS = ['x', 'y', 'type', 'datum', 'configure', 'tooltip', 'legend'];
let AXIS_NAMES = ['xAxis', 'yAxis','y1Axis', 'y2Axis','y3Axis' , 'y4Axis', 'x2Axis', 'yAxis1'];
let SIZE = ['width', 'height'];
let MARGIN = 'margin';
let LEGEND = 'legend';
let TOOLTIP = 'tooltip';
export default class NVD3Chart extends React.Component {
static propTypes: {
type: React.PropTypes.string.isRequired,
configure: React.PropTypes.func
}
/**
* Instantiate a new chart setting
* a callback if exists
*/
componentDidMount() {
nv.addGraph(this.renderChart.bind(this), this.props.renderEnd);
}
/**
* Update the chart after state is changed.
*/
componentDidUpdate() {
this.renderChart();
}
/**
* Remove listeners
*/
componentWillUnmount() {
this.resizeHandler.clear();
}
/**
* Creates a chart model and render it
*/
renderChart() {
// Margins are an special case. It needs to be
// passed to the margin function.
this.chart = this.chart || nv.models[this.props.type]();
this.chart
.x(this.getValueFunction(this.props.x, 'x'))
.y(this.getValueFunction(this.props.y, 'y'))
.margin(this.options(MARGIN, pick).margin || this.propsByPrefix('margin') || {})
.options(this.options(SETTINGS.concat(AXIS_NAMES, SIZE, MARGIN), without));
// We need to set the axis, legend and tooltip components separatly
this.configureComponents(this.chart, this.options(AXIS_NAMES.concat(TOOLTIP, LEGEND)));
// hook for configuring the chart
!this.props.configure || this.props.configure(this.chart);
// Render chart using d3
d3.select(this.refs.svg)
.datum(this.props.datum)
.call(this.chart);
// Update the chart if the window size change.
// Save resizeHandle to remove the resize listener later.
if(!this.resizeHandler)
this.resizeHandler = nv.utils.windowResize(this.chart.update);
return this.chart;
}
/**
* Configure components recursively
* @param {nvd3 chart} chart A nvd3 chart instance
* @param {object} options A key value object
*/
configureComponents(chart, options) {
for(let optionName in options){
let optionValue = options[optionName];
if(chart) {
if(typeof optionValue === 'object' && !(optionValue instanceof Array)){
this.configureComponents(chart[optionName], optionValue);
} else if(typeof chart[optionName] === 'function'){
chart[optionName](optionValue);
}
}
}
}
/**
* Filter options base on predicates
* @param {Array} keys An array of keys to preserve or remove
* @param {Function} predicate The function used to filter keys
*/
options(keys, predicate) {
if(this.props.chartOptions) console.warn('chartOptions is deprecated use options instead');
// DEPRECATED: this.props.chartOptions
let opt = this.props.options || this.props.chartOptions || this.props;
predicate = predicate || pick;
return predicate(opt, keys);
}
/**
* Allow to use either a value or a function to
* @param {[type]} v Either a getter or a function name
* @param {String} _default A default string used as getter
* @return {Function} Returns a function to use as getter
*/
getValueFunction(v, _default) {
if(typeof v === 'function') return v;
return (d) => { return typeof d[v] !== 'undefined' ? d[v] : d[_default]; }
}
/**
* Get properties using a prefix
* @param {String} prefix
* @return {[type]} Return an object with wanted keys
* DEPRECATED: This was created only for margins and
* since we changed the api we don't need this anymore.
*/
propsByPrefix(prefix) {
console.warn('Set margin with prefixes is deprecated use an object instead');
prefix = prefix + '-';
return Object.keys(this.props).reduce((memo, prop) => {
if (prop.startsWith(prefix)) memo[prop.replace(prefix, '')] = this.props[prop];
return memo;
}, {});
}
/**
* Render function
* svg element needs to have height and width.
*/
render() {
return (
<div ref="root" className="nv-chart">
<svg ref="svg" {...pick(this.props, SIZE)}></svg>
</div>
);
}
}
// Babel 6 issue: http://stackoverflow.com/questions/33505992/babel-6-changes-how-it-exports-default
module.exports = NVD3Chart;