@data-ui/sparkline
Version:
React + d3 library for creating sparklines
224 lines (199 loc) • 6.83 kB
JavaScript
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* eslint react/no-unused-prop-types: 0 */
import PropTypes from 'prop-types';
import React from 'react';
import { extent } from 'd3-array';
import Group from '@vx/group/build/Group';
import scaleLinear from '@vx/scale/build/scales/linear';
import BarSeries from '../series/BarSeries';
import { componentName, isBandLine, isReferenceLine, isSeries } from '../utils/componentIsX';
import isDefined from '../utils/defined';
var propTypes = {
ariaLabel: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
className: PropTypes.string,
// number or objects (with accessors)
data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.object])),
height: PropTypes.number.isRequired,
margin: PropTypes.shape({
top: PropTypes.number,
right: PropTypes.number,
bottom: PropTypes.number,
left: PropTypes.number
}),
max: PropTypes.number,
min: PropTypes.number,
onMouseMove: PropTypes.func,
onMouseLeave: PropTypes.func,
preserveAspectRatio: PropTypes.string,
styles: PropTypes.object,
// eslint-disable-line react/forbid-prop-types
width: PropTypes.number.isRequired,
valueAccessor: PropTypes.func,
viewBox: PropTypes.string
};
var defaultProps = {
className: null,
data: [],
margin: {
top: 16,
right: 16,
bottom: 16,
left: 16
},
max: null,
min: null,
onMouseMove: null,
onMouseLeave: null,
preserveAspectRatio: null,
styles: null,
valueAccessor: function valueAccessor(d) {
return d;
},
viewBox: null
};
var getX = function getX(d) {
return d.i;
};
var getY = function getY(d) {
return d.y;
};
var parsedDatumThunk = function parsedDatumThunk(valueAccessor) {
return function (d, i) {
var y = valueAccessor(d);
return _extends({
i: i,
y: y,
id: y
}, d);
};
};
var Sparkline =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(Sparkline, _React$PureComponent);
function Sparkline(props) {
var _this;
_this = _React$PureComponent.call(this, props) || this;
_this.getMaxY = _this.getMaxY.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.state = _this.getStateFromProps(props);
return _this;
}
var _proto = Sparkline.prototype;
_proto.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
var _this2 = this;
if ([// recompute scales if any of the following change
'data', 'height', 'margin', 'max', 'min', 'valueAccessor', 'width'].some(function (prop) {
return _this2.props[prop] !== nextProps[prop];
}) // eslint-disable-line react/destructuring-assignment
) {
this.setState(this.getStateFromProps(nextProps));
}
};
_proto.getStateFromProps = function getStateFromProps(props) {
var dimensions = this.getDimmensions(props);
var scales = this.getScales(props, dimensions);
return _extends({}, dimensions, scales);
};
_proto.getScales = function getScales(props, _ref) {
var innerHeight = _ref.innerHeight,
innerWidth = _ref.innerWidth;
var _ref2 = props || this.props,
rawData = _ref2.data,
min = _ref2.min,
max = _ref2.max,
valueAccessor = _ref2.valueAccessor;
var data = rawData.map(parsedDatumThunk(valueAccessor));
var yExtent = extent(data, getY);
var xScale = scaleLinear({
domain: [0, data.length - 1],
range: [0, innerWidth]
});
var yScale = scaleLinear({
domain: [isDefined(min) ? min : yExtent[0], isDefined(max) ? max : yExtent[1]],
range: [innerHeight, 0]
});
return {
xScale: xScale,
yScale: yScale,
data: data
};
};
_proto.getMaxY = function getMaxY() {
var yScale = this.state.yScale;
return Math.max.apply(Math, yScale.domain());
};
_proto.getDimmensions = function getDimmensions(props) {
var _ref3 = props || this.props,
margin = _ref3.margin,
width = _ref3.width,
height = _ref3.height;
var completeMargin = _extends({}, defaultProps.margin, margin);
return {
margin: completeMargin,
innerHeight: height - completeMargin.top - completeMargin.bottom,
innerWidth: width - completeMargin.left - completeMargin.right
};
};
_proto.render = function render() {
var _this$props = this.props,
ariaLabel = _this$props.ariaLabel,
children = _this$props.children,
className = _this$props.className,
height = _this$props.height,
onMouseMove = _this$props.onMouseMove,
onMouseLeave = _this$props.onMouseLeave,
preserveAspectRatio = _this$props.preserveAspectRatio,
styles = _this$props.styles,
width = _this$props.width,
viewBox = _this$props.viewBox;
var _this$state = this.state,
data = _this$state.data,
margin = _this$state.margin,
xScale = _this$state.xScale,
yScale = _this$state.yScale;
var seriesProps = {
xScale: xScale,
yScale: yScale,
data: data,
getX: getX,
getY: getY,
margin: margin
};
return React.createElement("svg", {
"aria-label": ariaLabel,
className: className,
height: height,
role: "img",
preserveAspectRatio: preserveAspectRatio,
style: styles,
width: width,
viewBox: viewBox
}, React.createElement(Group, {
left: margin.left,
top: margin.top
}, React.Children.map(children, function (Child) {
var name = componentName(Child);
if (isSeries(name) || isReferenceLine(name) || isBandLine(name)) {
return React.cloneElement(Child, seriesProps);
}
return Child;
}), (onMouseMove || onMouseLeave) && React.createElement(BarSeries, _extends({
fill: "transparent",
fillOpacity: 0,
stroke: "transparent",
strokeWidth: 1
}, seriesProps, {
getY: this.getMaxY,
onMouseMove: onMouseMove,
onMouseLeave: onMouseLeave
}))));
};
return Sparkline;
}(React.PureComponent);
Sparkline.propTypes = propTypes;
Sparkline.defaultProps = defaultProps;
Sparkline.displayName = 'Sparkline';
export default Sparkline;