UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

169 lines (152 loc) 8.1 kB
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;