UNPKG

@data-ui/histogram

Version:

React + d3 library for creating histograms

184 lines (177 loc) 5.87 kB
import PropTypes from 'prop-types'; import React from 'react'; import { NodeGroup } from 'react-move'; import { chartTheme } from '@data-ui/theme'; import { Group } from '@vx/group'; import { Bar } from '@vx/shape'; import callOrValue from '../../utils/callOrValue'; import { binnedDataShape } from '../../utils/propShapes'; var propTypes = { rawData: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])), // eslint-disable-line react/no-unused-prop-types binnedData: binnedDataShape, fill: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), fillOpacity: PropTypes.oneOfType([PropTypes.func, PropTypes.number]), horizontal: PropTypes.bool, stroke: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), strokeWidth: PropTypes.oneOfType([PropTypes.func, PropTypes.number]), valueKey: PropTypes.string, onClick: PropTypes.func, // likely injected by parent Histogram binScale: PropTypes.func, valueScale: PropTypes.func, onMouseMove: PropTypes.func, onMouseLeave: PropTypes.func, keyAccessor: PropTypes.func }; var defaultProps = { rawData: [], binnedData: [], binScale: null, fill: chartTheme.colors.default, fillOpacity: 0.7, horizontal: false, onClick: null, onMouseMove: null, onMouseLeave: null, stroke: '#FFFFFF', strokeWidth: 1, valueKey: 'count', valueScale: null, keyAccessor: function keyAccessor(d) { return d.id; } }; var INDEX_DELAY_MULTIPLIER = 10; var getBin = function getBin(d) { return typeof d.bin === 'undefined' ? d.bin0 : d.bin; }; var getBin1 = function getBin1(d) { return typeof d.bin === 'undefined' ? d.bin1 : d.bin; }; function AnimatedBarSeries(_ref) { var binnedData = _ref.binnedData, valueScale = _ref.valueScale, binScale = _ref.binScale, horizontal = _ref.horizontal, keyAccessor = _ref.keyAccessor, fill = _ref.fill, fillOpacity = _ref.fillOpacity, onClick = _ref.onClick, onMouseMove = _ref.onMouseMove, onMouseLeave = _ref.onMouseLeave, stroke = _ref.stroke, strokeWidth = _ref.strokeWidth, valueKey = _ref.valueKey; var maxBarLength = Math.max.apply(Math, valueScale.range()); // compute once and use throughout var barWidths = binnedData.map(function (_, i) { return binScale.bandwidth ? binScale.bandwidth() // categorical : Math.abs(binScale(binnedData[i].bin1) - binScale(binnedData[i].bin0)); } // numeric ); var getValue = function getValue(d) { return d[valueKey]; }; var getX = horizontal ? getValue : getBin; var getY = horizontal ? getBin1 : getValue; var xScale = horizontal ? valueScale : binScale; var yScale = horizontal ? binScale : valueScale; return React.createElement(NodeGroup, { data: binnedData, keyAccessor: keyAccessor, start: function start(d, i) { return { x: horizontal ? 0 : xScale(getX(d)), y: horizontal ? yScale(getY(d)) : maxBarLength, fill: d.fill || callOrValue(fill, d, i), width: horizontal ? 0 : barWidths[i], height: horizontal ? barWidths[i] : 0 }; }, enter: function enter(d, i) { return { x: [horizontal ? 0 : xScale(getX(d))], y: [yScale(getY(d))], width: [horizontal ? xScale(getX(d)) : barWidths[i]], height: [horizontal ? barWidths[i] : maxBarLength - yScale(getY(d))], fill: [d.fill || callOrValue(fill, d, i)], stroke: [d.stroke || callOrValue(stroke, d, i)], timing: { duration: 300, delay: INDEX_DELAY_MULTIPLIER * i } }; }, update: function update(d, i) { return { x: [horizontal ? 0 : xScale(getX(d))], y: [yScale(getY(d))], width: [horizontal ? xScale(getX(d)) : barWidths[i]], height: [horizontal ? barWidths[i] : maxBarLength - yScale(getY(d))], fill: [d.fill || callOrValue(fill, d, i)], stroke: [d.stroke || callOrValue(stroke, d, i)], timing: { duration: 300, delay: INDEX_DELAY_MULTIPLIER * i } }; }, leave: function leave(d, i) { return { x: horizontal ? 0 : xScale(getX(d)), y: horizontal ? yScale(getY(d)) : maxBarLength, width: horizontal ? 0 : barWidths[i], height: horizontal ? barWidths[i] : 0, timing: { duration: 300, delay: INDEX_DELAY_MULTIPLIER / 2 * i } }; } }, function (data) { return React.createElement(Group, null, data.map(function (modifiedDatum, i) { var key = modifiedDatum.key, rawDatum = modifiedDatum.data, d = modifiedDatum.state; return React.createElement(Bar, { key: "bar" + key, x: d.x, y: d.y, width: d.width, height: d.height, fill: d.fill, stroke: d.stroke, fillOpacity: typeof fillOpacity === 'undefined' ? callOrValue(fillOpacity, rawDatum, i) : fillOpacity, strokeWidth: rawDatum.strokeWidth || callOrValue(strokeWidth, rawDatum, i), onClick: onClick && function () { return function (event) { onClick({ event: event, datum: rawDatum, data: binnedData, color: d.fill, index: i }); }; }, onMouseMove: onMouseMove && function () { return function (event) { onMouseMove({ event: event, datum: rawDatum, data: binnedData, color: d.fill, index: i }); }; }, onMouseLeave: onMouseLeave && function () { return onMouseLeave; } }); })); }); } AnimatedBarSeries.propTypes = propTypes; AnimatedBarSeries.defaultProps = defaultProps; export default AnimatedBarSeries;