lucid-ui
Version:
A UI component library from AppNexus.
169 lines (152 loc) • 8.1 kB
JavaScript
import _map from "lodash/map";
import _keys from "lodash/keys";
import _identity from "lodash/identity";
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); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
import React from 'react';
import PropTypes from 'react-peek/prop-types';
import { lucidClassNames } from '../../util/style-helpers';
import { discreteTicks } from '../../util/chart-helpers';
import { omitProps } from '../../util/component-types';
var cx = lucidClassNames.bind('&-Axis');
var string = PropTypes.string,
array = PropTypes.array,
func = PropTypes.func,
number = PropTypes.number,
oneOf = PropTypes.oneOf;
var defaultProps = {
innerTickSize: 6,
// same as d3
outerTickSize: 6,
// same as d3
tickPadding: 3,
// same as d3
textOrientation: 'horizontal',
orient: 'bottom',
tickCount: null
};
export var Axis = function Axis(props) {
var className = props.className,
scale = props.scale,
orient = props.orient,
tickCount = props.tickCount,
_props$ticks = props.ticks,
ticks = _props$ticks === void 0 ? 'ticks' in scale ? scale.ticks(tickCount) : discreteTicks(scale.domain(), tickCount) : _props$ticks,
innerTickSize = props.innerTickSize,
outerTickSize = props.outerTickSize,
_props$tickFormat = props.tickFormat,
tickFormat = _props$tickFormat === void 0 ? 'tickFormat' in scale ? scale.tickFormat() : _identity : _props$tickFormat,
tickPadding = props.tickPadding,
textOrientation = props.textOrientation,
passThroughs = _objectWithoutProperties(props, ["className", "scale", "orient", "tickCount", "ticks", "innerTickSize", "outerTickSize", "tickFormat", "tickPadding", "textOrientation"]);
var tickSpacing = Math.max(innerTickSize, 0) + tickPadding; // Domain
var range = scale.range();
var sign = orient === 'top' || orient === 'left' ? -1 : 1;
var isH = orient === 'top' || orient === 'bottom'; // is horizontal
var getOrientationProperties = function getOrientationProperties(orient, textOrientation) {
var textAnchor, x, y, dy;
var orientationSign = sign;
var transform = textOrientation === 'vertical' ? 'rotate(-90)' : textOrientation === 'horizontal' ? '' : 'rotate(-30)';
switch (orient) {
case 'bottom':
if (textOrientation === 'vertical') {
orientationSign = -orientationSign;
}
textAnchor = textOrientation === 'vertical' ? 'end' : textOrientation === 'diagonal' ? 'end' : 'middle';
x = textOrientation === 'vertical' ? orientationSign * tickSpacing : textOrientation === 'diagonal' ? -orientationSign * tickSpacing : 0;
y = textOrientation === 'vertical' ? 0 : orientationSign * tickSpacing;
dy = textOrientation === 'vertical' ? '.32em' : '.71em';
break;
case 'top':
if (textOrientation === 'vertical') {
orientationSign = -orientationSign;
}
textAnchor = textOrientation === 'vertical' ? 'start' : textOrientation === 'diagonal' ? 'start' : 'middle';
x = textOrientation === 'vertical' || textOrientation === 'diagonal' ? -orientationSign * tickSpacing : 0;
y = textOrientation === 'vertical' ? 0 : orientationSign * tickSpacing;
dy = textOrientation === 'vertical' || textOrientation === 'diagonal' ? '.32em' : '0em';
break;
case 'right':
textAnchor = textOrientation === 'vertical' ? 'middle' : 'start';
x = textOrientation === 'vertical' ? 0 : orientationSign * tickSpacing;
y = textOrientation === 'vertical' ? orientationSign * tickSpacing : textOrientation === 'horizontal' ? 0 : orientationSign * tickSpacing;
dy = textOrientation === 'vertical' ? '.71em' : '.32em';
break;
case 'left':
textAnchor = textOrientation === 'vertical' ? 'middle' : 'end';
x = textOrientation === 'vertical' ? 0 : orientationSign * tickSpacing;
y = textOrientation === 'vertical' || textOrientation === 'diagonal' ? orientationSign * tickSpacing : 0;
dy = textOrientation === 'vertical' ? '0em' : textOrientation === 'horizontal' ? '.32em' : '.71em';
break;
default:
textAnchor = 'start';
x = 0;
y = 0;
dy = 'null';
}
return {
transform: transform,
textAnchor: textAnchor,
x: x,
y: y,
dy: dy
};
};
var orientationProperties = {
vertical: getOrientationProperties(orient, 'vertical'),
horizontal: getOrientationProperties(orient, 'horizontal'),
diagonal: getOrientationProperties(orient, 'diagonal')
};
var orientationKey = textOrientation || 'horizontal'; // Only band scales have `bandwidth`, this conditional helps center the
// ticks on the bands
var scaleNormalized = 'bandwidth' in scale ? function (d) {
return scale(d) + scale.bandwidth() / 2;
} : scale;
return /*#__PURE__*/React.createElement("g", _extends({}, omitProps(passThroughs, undefined, _keys(Axis.propTypes)), {
className: cx(className, '&')
}), isH ? /*#__PURE__*/React.createElement("path", {
className: cx('&-domain'),
d: "M".concat(range[0], ",").concat(sign * outerTickSize, "V0H").concat(range[1], "V").concat(sign * outerTickSize)
}) : /*#__PURE__*/React.createElement("path", {
className: cx('&-domain'),
d: "M".concat(sign * outerTickSize, ",").concat(range[0], "H0V").concat(range[1], "H").concat(sign * outerTickSize)
}), _map(ticks, function (tick) {
return /*#__PURE__*/React.createElement("g", {
key: tick,
transform: "translate(".concat(isH ? scaleNormalized(tick) : 0, ", ").concat(isH ? 0 : scaleNormalized(tick), ")")
}, /*#__PURE__*/React.createElement("line", {
className: cx('&-tick'),
x2: isH ? 0 : sign * innerTickSize,
y2: isH ? sign * innerTickSize : 0
}), /*#__PURE__*/React.createElement("text", {
className: cx('&-tick-text'),
x: orientationProperties[orientationKey].x,
y: orientationProperties[orientationKey].y,
dy: orientationProperties[orientationKey].dy,
style: {
textAnchor: orientationProperties[orientationKey].textAnchor
},
transform: orientationProperties[orientationKey].transform
}, tickFormat(tick)));
}));
};
Axis.defaultProps = defaultProps;
Axis.displayName = 'Axis';
Axis.peek = {
description: "\n\t*`Axis` is used within an `svg`*\n\tAn `Axis` is used to help render human-readable reference marks on charts.\n\tIt can either be horizontal or vertical and really only needs a scale\n\tto be able to draw properly.\n\tThis component is a very close sister to d3's svg axis and most of the\n\tlogic was ported from there.\n\t",
categories: ['visualizations', 'chart primitives']
};
Axis.propTypes = {
className: string,
scale: func.isRequired,
innerTickSize: number,
outerTickSize: number,
tickFormat: func,
ticks: array,
tickPadding: number,
orient: oneOf(['top', 'bottom', 'left', 'right']),
tickCount: number,
textOrientation: oneOf(['vertical', 'horizontal', 'diagonal'])
};
export default Axis;