No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

927 líneas
29 KiB

  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _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; };
  6. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  7. var _SCALE_FUNCTIONS;
  8. exports._getSmallestDistanceIndex = _getSmallestDistanceIndex;
  9. exports.getScaleFnFromScaleObject = getScaleFnFromScaleObject;
  10. exports.getDomainByAccessor = getDomainByAccessor;
  11. exports._getScaleDistanceAndAdjustedDomain = _getScaleDistanceAndAdjustedDomain;
  12. exports._adjustCategoricalScale = _adjustCategoricalScale;
  13. exports.getScaleObjectFromProps = getScaleObjectFromProps;
  14. exports.getAttributeScale = getAttributeScale;
  15. exports.getAttributeFunctor = getAttributeFunctor;
  16. exports.getAttr0Functor = getAttr0Functor;
  17. exports.getAttributeValue = getAttributeValue;
  18. exports.getScalePropTypesByAttribute = getScalePropTypesByAttribute;
  19. exports.extractScalePropsFromProps = extractScalePropsFromProps;
  20. exports.getMissingScaleProps = getMissingScaleProps;
  21. exports.literalScale = literalScale;
  22. exports.getFontColorFromBackground = getFontColorFromBackground;
  23. exports.getXYPlotValues = getXYPlotValues;
  24. exports.getOptionalScaleProps = getOptionalScaleProps;
  25. var _d3Scale = require('d3-scale');
  26. var _d3Array = require('d3-array');
  27. var _d3Collection = require('d3-collection');
  28. var _d3Color = require('d3-color');
  29. var _propTypes = require('prop-types');
  30. var _propTypes2 = _interopRequireDefault(_propTypes);
  31. var _reactUtils = require('./react-utils');
  32. var _dataUtils = require('./data-utils');
  33. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  34. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  35. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } // Copyright (c) 2016 - 2017 Uber Technologies, Inc.
  36. //
  37. // Permission is hereby granted, free of charge, to any person obtaining a copy
  38. // of this software and associated documentation files (the "Software"), to deal
  39. // in the Software without restriction, including without limitation the rights
  40. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  41. // copies of the Software, and to permit persons to whom the Software is
  42. // furnished to do so, subject to the following conditions:
  43. //
  44. // The above copyright notice and this permission notice shall be included in
  45. // all copies or substantial portions of the Software.
  46. //
  47. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  48. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  49. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  50. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  51. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  52. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  53. // THE SOFTWARE.
  54. /**
  55. * Linear scale name.
  56. * @type {string}
  57. * @const
  58. */
  59. var LINEAR_SCALE_TYPE = 'linear';
  60. /**
  61. * Ordinal scale name.
  62. * @type {string}
  63. * @const
  64. */
  65. var ORDINAL_SCALE_TYPE = 'ordinal';
  66. /**
  67. * Category scale.
  68. * @type {string}
  69. * @const
  70. */
  71. var CATEGORY_SCALE_TYPE = 'category';
  72. /**
  73. * Literal scale.
  74. * Differs slightly from d3's identity scale in that it does not coerce value
  75. * into numbers, it simply returns exactly what you give it
  76. * @type {string}
  77. * @const
  78. */
  79. var LITERAL_SCALE_TYPE = 'literal';
  80. /**
  81. * Log scale name.
  82. * @type {string}
  83. * @const
  84. */
  85. var LOG_SCALE_TYPE = 'log';
  86. /**
  87. * Time scale name.
  88. * @type {string}
  89. * @const
  90. */
  91. var TIME_SCALE_TYPE = 'time';
  92. /**
  93. * Time UTC scale name.
  94. * @type {string}
  95. * @const
  96. */
  97. var TIME_UTC_SCALE_TYPE = 'time-utc';
  98. /**
  99. * Scale functions that are supported in the library.
  100. * @type {Object}
  101. * @const
  102. */
  103. var SCALE_FUNCTIONS = (_SCALE_FUNCTIONS = {}, _defineProperty(_SCALE_FUNCTIONS, LINEAR_SCALE_TYPE, _d3Scale.scaleLinear), _defineProperty(_SCALE_FUNCTIONS, ORDINAL_SCALE_TYPE, _d3Scale.scalePoint), _defineProperty(_SCALE_FUNCTIONS, CATEGORY_SCALE_TYPE, _d3Scale.scaleOrdinal), _defineProperty(_SCALE_FUNCTIONS, LITERAL_SCALE_TYPE, literalScale), _defineProperty(_SCALE_FUNCTIONS, LOG_SCALE_TYPE, _d3Scale.scaleLog), _defineProperty(_SCALE_FUNCTIONS, TIME_SCALE_TYPE, _d3Scale.scaleTime), _defineProperty(_SCALE_FUNCTIONS, TIME_UTC_SCALE_TYPE, _d3Scale.scaleUtc), _SCALE_FUNCTIONS);
  104. /**
  105. * Attrs for which a scale can be set up at XYPlot level
  106. * @type {Array}
  107. * @const
  108. */
  109. var XYPLOT_ATTR = ['color', 'fill', 'opacity', 'stroke'];
  110. /**
  111. * Title case a given string
  112. * @param {String} str Array of values.
  113. * @returns {String} titlecased string
  114. */
  115. function toTitleCase(str) {
  116. return '' + str[0].toUpperCase() + str.slice(1);
  117. }
  118. /**
  119. * Find the smallest distance between the values on a given scale and return
  120. * the index of the element, where the smallest distance was found.
  121. * It returns the first occurrence of i where
  122. * `scale(value[i]) - scale(value[i - 1])` is minimal
  123. * @param {Array} values Array of values.
  124. * @param {Object} scaleObject Scale object.
  125. * @returns {number} Index of an element where the smallest distance was found.
  126. * @private
  127. */
  128. function _getSmallestDistanceIndex(values, scaleObject) {
  129. var scaleFn = getScaleFnFromScaleObject(scaleObject);
  130. var result = 0;
  131. if (scaleFn) {
  132. var nextValue = void 0;
  133. var currentValue = scaleFn(values[0]);
  134. var distance = Infinity;
  135. var nextDistance = void 0;
  136. for (var i = 1; i < values.length; i++) {
  137. nextValue = scaleFn(values[i]);
  138. nextDistance = Math.abs(nextValue - currentValue);
  139. if (nextDistance < distance) {
  140. distance = nextDistance;
  141. result = i;
  142. }
  143. currentValue = nextValue;
  144. }
  145. }
  146. return result;
  147. }
  148. /**
  149. * This is a workaround for issue that ordinal scale
  150. * does not have invert method implemented in d3-scale.
  151. * @param {Object} Ordinal d3-scale object.
  152. * @returns {void}
  153. * @private
  154. */
  155. function addInvertFunctionToOrdinalScaleObject(scale) {
  156. if (scale.invert) {
  157. return;
  158. }
  159. scale.invert = function invert(value) {
  160. var _scale$range = scale.range(),
  161. _scale$range2 = _slicedToArray(_scale$range, 2),
  162. lower = _scale$range2[0],
  163. upper = _scale$range2[1];
  164. var start = Math.min(lower, upper);
  165. var stop = Math.max(lower, upper);
  166. if (value < start + scale.padding() * scale.step()) {
  167. return scale.domain()[0];
  168. }
  169. if (value > stop - scale.padding() * scale.step()) {
  170. return scale.domain()[scale.domain().length - 1];
  171. }
  172. var index = Math.floor((value - start - scale.padding() * scale.step()) / scale.step());
  173. return scale.domain()[index];
  174. };
  175. }
  176. /**
  177. * Crate a scale function from the scale object.
  178. * @param {Object} scaleObject Scale object.
  179. - scaleObject.domain {Array}
  180. - scaleObject.range {Array}
  181. - scaleObject.type {string}
  182. - scaleObject.attr {string}
  183. * @returns {*} Scale function.
  184. * @private
  185. */
  186. function getScaleFnFromScaleObject(scaleObject) {
  187. if (!scaleObject) {
  188. return null;
  189. }
  190. var type = scaleObject.type,
  191. domain = scaleObject.domain,
  192. range = scaleObject.range;
  193. var modDomain = domain[0] === domain[1] ? domain[0] === 0 ? [-1, 0] : [-domain[0], domain[0]] : domain;
  194. if (type === LITERAL_SCALE_TYPE) {
  195. return literalScale(range[0]);
  196. }
  197. var scale = SCALE_FUNCTIONS[type]().domain(modDomain).range(range);
  198. if (type === ORDINAL_SCALE_TYPE) {
  199. scale.padding(0.5);
  200. addInvertFunctionToOrdinalScaleObject(scale);
  201. }
  202. return scale;
  203. }
  204. /**
  205. * Get the domain from the array of data.
  206. * @param {Array} allData All data.
  207. * @param {function} accessor - accessor for main value.
  208. * @param {function} accessor0 - accessor for the naught value.
  209. * @param {string} type Scale type.
  210. * @returns {Array} Domain.
  211. * @private
  212. */
  213. function getDomainByAccessor(allData, accessor, accessor0, type) {
  214. var domain = void 0;
  215. // Collect both attr and available attr0 values from the array of data.
  216. var values = allData.reduce(function (data, d) {
  217. var value = accessor(d);
  218. var value0 = accessor0(d);
  219. if (_isDefined(value)) {
  220. data.push(value);
  221. }
  222. if (_isDefined(value0)) {
  223. data.push(value0);
  224. }
  225. return data;
  226. }, []);
  227. if (!values.length) {
  228. return [];
  229. }
  230. // Create proper domain depending on the type of the scale.
  231. if (type !== ORDINAL_SCALE_TYPE && type !== CATEGORY_SCALE_TYPE) {
  232. domain = (0, _d3Array.extent)(values);
  233. } else {
  234. domain = (0, _d3Collection.set)(values).values();
  235. }
  236. return domain;
  237. }
  238. /**
  239. * Create custom scale object from the value. When the scale is created from
  240. * this object, it should return the same value all time.
  241. * @param {string} attr Attribute.
  242. * @param {*} value Value.
  243. * @param {string} type - the type of scale being used
  244. * @param {function} accessor - the accessor function
  245. * @param {function} accessor0 - the accessor function for the potential naught value
  246. * @returns {Object} Custom scale object.
  247. * @private
  248. */
  249. function _createScaleObjectForValue(attr, value, type, accessor, accessor0) {
  250. if (type === LITERAL_SCALE_TYPE) {
  251. return {
  252. type: LITERAL_SCALE_TYPE,
  253. domain: [],
  254. range: [value],
  255. distance: 0,
  256. attr: attr,
  257. baseValue: undefined,
  258. isValue: true,
  259. accessor: accessor,
  260. accessor0: accessor0
  261. };
  262. }
  263. if (typeof value === 'undefined') {
  264. return null;
  265. }
  266. return {
  267. type: CATEGORY_SCALE_TYPE,
  268. range: [value],
  269. domain: [],
  270. distance: 0,
  271. attr: attr,
  272. baseValue: undefined,
  273. isValue: true,
  274. accessor: accessor,
  275. accessor0: accessor0
  276. };
  277. }
  278. /**
  279. * Create a regular scale object for a further use from the existing parameters.
  280. * @param {Array} domain - Domain.
  281. * @param {Array} range - Range.
  282. * @param {string} type - Type.
  283. * @param {number} distance - Distance.
  284. * @param {string} attr - Attribute.
  285. * @param {number} baseValue - Base value.
  286. * @param {function} accessor - Attribute accesor
  287. * @param {function} accessor0 - Attribute accesor for potential naught value
  288. * @returns {Object} Scale object.
  289. * @private
  290. */
  291. function _createScaleObjectForFunction(_ref) {
  292. var domain = _ref.domain,
  293. range = _ref.range,
  294. type = _ref.type,
  295. distance = _ref.distance,
  296. attr = _ref.attr,
  297. baseValue = _ref.baseValue,
  298. accessor = _ref.accessor,
  299. accessor0 = _ref.accessor0;
  300. return {
  301. domain: domain,
  302. range: range,
  303. type: type,
  304. distance: distance,
  305. attr: attr,
  306. baseValue: baseValue,
  307. isValue: false,
  308. accessor: accessor,
  309. accessor0: accessor0
  310. };
  311. }
  312. /**
  313. * Get scale object from props. E. g. object like {xRange, xDomain, xDistance,
  314. * xType} is transformed into {range, domain, distance, type}.
  315. * @param {Object} props Props.
  316. * @param {string} attr Attribute.
  317. * @returns {*} Null or an object with the scale.
  318. * @private
  319. */
  320. function _collectScaleObjectFromProps(props, attr) {
  321. var value = props[attr],
  322. fallbackValue = props['_' + attr + 'Value'],
  323. range = props[attr + 'Range'],
  324. _props$ = props[attr + 'Distance'],
  325. distance = _props$ === undefined ? 0 : _props$,
  326. baseValue = props[attr + 'BaseValue'],
  327. _props$2 = props[attr + 'Type'],
  328. type = _props$2 === undefined ? LINEAR_SCALE_TYPE : _props$2,
  329. noFallBack = props[attr + 'NoFallBack'],
  330. _props$3 = props['get' + toTitleCase(attr)],
  331. accessor = _props$3 === undefined ? function (d) {
  332. return d[attr];
  333. } : _props$3,
  334. _props$4 = props['get' + toTitleCase(attr) + '0'],
  335. accessor0 = _props$4 === undefined ? function (d) {
  336. return d[attr + '0'];
  337. } : _props$4;
  338. var domain = props[attr + 'Domain'];
  339. // Return value-based scale if the value is assigned.
  340. if (!noFallBack && typeof value !== 'undefined') {
  341. return _createScaleObjectForValue(attr, value, props[attr + 'Type'], accessor, accessor0);
  342. }
  343. // Pick up the domain from the properties and create a new one if it's not
  344. // available.
  345. if (typeof baseValue !== 'undefined') {
  346. domain = (0, _dataUtils.addValueToArray)(domain, baseValue);
  347. }
  348. // Make sure that the minimum necessary properties exist.
  349. if (!range || !domain || !domain.length) {
  350. // Try to use the fallback value if it is available.
  351. return _createScaleObjectForValue(attr, fallbackValue, props[attr + 'Type'], accessor, accessor0);
  352. }
  353. return _createScaleObjectForFunction({
  354. domain: domain,
  355. range: range,
  356. type: type,
  357. distance: distance,
  358. attr: attr,
  359. baseValue: baseValue,
  360. accessor: accessor,
  361. accessor0: accessor0
  362. });
  363. }
  364. /**
  365. * Compute left domain adjustment for the given values.
  366. * @param {Array} values Array of values.
  367. * @returns {number} Domain adjustment.
  368. * @private
  369. */
  370. function _computeLeftDomainAdjustment(values) {
  371. if (values.length > 1) {
  372. return (values[1] - values[0]) / 2;
  373. }
  374. if (values.length === 1) {
  375. return values[0] - 0.5;
  376. }
  377. return 0;
  378. }
  379. /**
  380. * Compute right domain adjustment for the given values.
  381. * @param {Array} values Array of values.
  382. * @returns {number} Domain adjustment.
  383. * @private
  384. */
  385. function _computeRightDomainAdjustment(values) {
  386. if (values.length > 1) {
  387. return (values[values.length - 1] - values[values.length - 2]) / 2;
  388. }
  389. if (values.length === 1) {
  390. return values[0] - 0.5;
  391. }
  392. return 0;
  393. }
  394. /**
  395. * Compute distance for the given values.
  396. * @param {Array} values Array of values.
  397. * @param {Array} domain Domain.
  398. * @param {number} bestDistIndex Index of a best distance found.
  399. * @param {function} scaleFn Scale function.
  400. * @returns {number} Domain adjustment.
  401. * @private
  402. */
  403. function _computeScaleDistance(values, domain, bestDistIndex, scaleFn) {
  404. if (values.length > 1) {
  405. // Avoid zero indexes.
  406. var i = Math.max(bestDistIndex, 1);
  407. return Math.abs(scaleFn(values[i]) - scaleFn(values[i - 1]));
  408. }
  409. if (values.length === 1) {
  410. return Math.abs(scaleFn(domain[1]) - scaleFn(domain[0]));
  411. }
  412. return 0;
  413. }
  414. /**
  415. * Normilize array of values with a single value.
  416. * @param {Array} arr Array of data.
  417. * @param {Array} values Array of values.
  418. * @param {string} attr Attribute.
  419. * @param {string} type Type.
  420. * @private
  421. */
  422. function _normalizeValues(data, values, accessor0, type) {
  423. if (type === TIME_SCALE_TYPE && values.length === 1) {
  424. var attr0 = accessor0(data[0]);
  425. return [attr0].concat(_toConsumableArray(values));
  426. }
  427. return values;
  428. }
  429. /**
  430. * Get the distance, the smallest and the largest value of the domain.
  431. * @param {Array} data Array of data for the single series.
  432. * @param {Object} scaleObject Scale object.
  433. * @returns {{domain0: number, domainN: number, distance: number}} Result.
  434. * @private
  435. */
  436. function _getScaleDistanceAndAdjustedDomain(data, scaleObject) {
  437. var domain = scaleObject.domain,
  438. type = scaleObject.type,
  439. accessor = scaleObject.accessor,
  440. accessor0 = scaleObject.accessor0;
  441. var uniqueValues = (0, _dataUtils.getUniquePropertyValues)(data, accessor);
  442. // Fix time scale if a data has only one value.
  443. var values = _normalizeValues(data, uniqueValues, accessor0, type);
  444. var index = _getSmallestDistanceIndex(values, scaleObject);
  445. var adjustedDomain = [].concat(domain);
  446. adjustedDomain[0] -= _computeLeftDomainAdjustment(values);
  447. adjustedDomain[domain.length - 1] += _computeRightDomainAdjustment(values);
  448. // Fix log scale if it's too small.
  449. if (type === LOG_SCALE_TYPE && domain[0] <= 0) {
  450. adjustedDomain[0] = Math.min(domain[1] / 10, 1);
  451. }
  452. var adjustedScaleFn = getScaleFnFromScaleObject(_extends({}, scaleObject, {
  453. domain: adjustedDomain
  454. }));
  455. var distance = _computeScaleDistance(values, adjustedDomain, index, adjustedScaleFn);
  456. return {
  457. domain0: adjustedDomain[0],
  458. domainN: adjustedDomain[adjustedDomain.length - 1],
  459. distance: distance
  460. };
  461. }
  462. /**
  463. * Returns true if scale adjustments are possible for a given scale.
  464. * @param {Object} props Props.
  465. * @param {Object} scaleObject Scale object.
  466. * @returns {boolean} True if scale adjustments possible.
  467. * @private
  468. */
  469. function _isScaleAdjustmentPossible(props, scaleObject) {
  470. var attr = scaleObject.attr;
  471. var _props$_adjustBy = props._adjustBy,
  472. adjustBy = _props$_adjustBy === undefined ? [] : _props$_adjustBy,
  473. _props$_adjustWhat = props._adjustWhat,
  474. adjustWhat = _props$_adjustWhat === undefined ? [] : _props$_adjustWhat;
  475. // The scale cannot be adjusted if there's no attributes to adjust, no
  476. // suitable values
  477. return adjustWhat.length && adjustBy.length && adjustBy.indexOf(attr) !== -1;
  478. }
  479. /**
  480. * Adjust continuous scales (e.g. 'linear', 'log' and 'time') by adding the
  481. * space from the left and right of them and by computing the best distance.
  482. * @param {Object} props Props.
  483. * @param {Object} scaleObject Scale object.
  484. * @returns {*} Scale object with adjustments.
  485. * @private
  486. */
  487. function _adjustContinuousScale(props, scaleObject) {
  488. var allSeriesData = props._allData,
  489. _props$_adjustWhat2 = props._adjustWhat,
  490. adjustWhat = _props$_adjustWhat2 === undefined ? [] : _props$_adjustWhat2;
  491. // Assign the initial values.
  492. var domainLength = scaleObject.domain.length;
  493. var domain = scaleObject.domain;
  494. var scaleDomain0 = domain[0];
  495. var scaleDomainN = domain[domainLength - 1];
  496. var scaleDistance = scaleObject.distance;
  497. // Find the smallest left position of the domain, the largest right position
  498. // of the domain and the best distance for them.
  499. allSeriesData.forEach(function (data, index) {
  500. if (adjustWhat.indexOf(index) === -1) {
  501. return;
  502. }
  503. if (data && data.length) {
  504. var _getScaleDistanceAndA = _getScaleDistanceAndAdjustedDomain(data, scaleObject),
  505. domain0 = _getScaleDistanceAndA.domain0,
  506. domainN = _getScaleDistanceAndA.domainN,
  507. distance = _getScaleDistanceAndA.distance;
  508. scaleDomain0 = Math.min(scaleDomain0, domain0);
  509. scaleDomainN = Math.max(scaleDomainN, domainN);
  510. scaleDistance = Math.max(scaleDistance, distance);
  511. }
  512. });
  513. scaleObject.domain = [scaleDomain0].concat(_toConsumableArray(domain.slice(1, -1)), [scaleDomainN]);
  514. scaleObject.distance = scaleDistance;
  515. return scaleObject;
  516. }
  517. /**
  518. * Get an adjusted scale. Suitable for 'category' and 'ordinal' scales.
  519. * @param {Object} scaleObject Scale object.
  520. * @returns {*} Scale object with adjustments.
  521. * @private
  522. */
  523. function _adjustCategoricalScale(scaleObject) {
  524. var scaleFn = getScaleFnFromScaleObject(scaleObject);
  525. var domain = scaleObject.domain,
  526. range = scaleObject.range;
  527. if (domain.length > 1) {
  528. scaleObject.distance = Math.abs(scaleFn(domain[1]) - scaleFn(domain[0]));
  529. } else {
  530. scaleObject.distance = Math.abs(range[1] - range[0]);
  531. }
  532. return scaleObject;
  533. }
  534. /**
  535. * Retrieve a scale object or a value from the properties passed.
  536. * @param {Object} props Object of props.
  537. * @param {string} attr Attribute.
  538. * @returns {*} Scale object, value or null.
  539. */
  540. function getScaleObjectFromProps(props, attr) {
  541. // Create the initial scale object.
  542. var scaleObject = _collectScaleObjectFromProps(props, attr);
  543. if (!scaleObject) {
  544. return null;
  545. }
  546. // Make sure if it's possible to add space to the scale object. If not,
  547. // return the object immediately.
  548. if (!_isScaleAdjustmentPossible(props, scaleObject)) {
  549. return scaleObject;
  550. }
  551. var type = scaleObject.type;
  552. // Depending on what type the scale is, apply different adjustments. Distances
  553. // for the ordinal and category scales are even, equal domains cannot be
  554. // adjusted.
  555. if (type === ORDINAL_SCALE_TYPE || type === CATEGORY_SCALE_TYPE) {
  556. return _adjustCategoricalScale(scaleObject);
  557. }
  558. return _adjustContinuousScale(props, scaleObject);
  559. }
  560. /**
  561. * Get d3 scale for a given prop.
  562. * @param {Object} props Props.
  563. * @param {string} attr Attribute.
  564. * @returns {function} d3 scale function.
  565. */
  566. function getAttributeScale(props, attr) {
  567. var scaleObject = getScaleObjectFromProps(props, attr);
  568. return getScaleFnFromScaleObject(scaleObject);
  569. }
  570. /**
  571. * Get the value of `attr` from the object.
  572. * @param {Object} d - data Object.
  573. * @param {Function} accessor - accessor function.
  574. * @returns {*} Value of the point.
  575. * @private
  576. */
  577. function _getAttrValue(d, accessor) {
  578. return accessor(d.data ? d.data : d);
  579. }
  580. function _isDefined(value) {
  581. return typeof value !== 'undefined';
  582. }
  583. /*
  584. * Adds a percentage of padding to a given domain
  585. * @param {Array} domain X or Y domain to pad.
  586. * @param {Number} padding Percentage of padding to add to domain
  587. * @returns {Array} Padded Domain
  588. */
  589. function _padDomain(domain, padding) {
  590. if (!domain) {
  591. return domain;
  592. }
  593. if (isNaN(parseFloat(domain[0])) || isNaN(parseFloat(domain[1]))) {
  594. return domain;
  595. }
  596. var _domain = _slicedToArray(domain, 2),
  597. min = _domain[0],
  598. max = _domain[1];
  599. var domainPadding = (max - min) * (padding * 0.01);
  600. return [min - domainPadding, max + domainPadding];
  601. }
  602. /**
  603. * Get prop functor (either a value or a function) for a given attribute.
  604. * @param {Object} props Series props.
  605. * @param {Function} accessor - Property accessor.
  606. * @returns {*} Function or value.
  607. */
  608. function getAttributeFunctor(props, attr) {
  609. var scaleObject = getScaleObjectFromProps(props, attr);
  610. if (scaleObject) {
  611. var scaleFn = getScaleFnFromScaleObject(scaleObject);
  612. return function (d) {
  613. return scaleFn(_getAttrValue(d, scaleObject.accessor));
  614. };
  615. }
  616. return null;
  617. }
  618. /**
  619. * Get the functor which extracts value form [attr]0 property. Use baseValue if
  620. * no attr0 property for a given object is defined. Fall back to domain[0] if no
  621. * base value is available.
  622. * @param {Object} props Object of props.
  623. * @param {string} attr Attribute name.
  624. * @returns {*} Function which returns value or null if no values available.
  625. */
  626. function getAttr0Functor(props, attr) {
  627. var scaleObject = getScaleObjectFromProps(props, attr);
  628. if (scaleObject) {
  629. var domain = scaleObject.domain;
  630. var _scaleObject$baseValu = scaleObject.baseValue,
  631. baseValue = _scaleObject$baseValu === undefined ? domain[0] : _scaleObject$baseValu;
  632. var scaleFn = getScaleFnFromScaleObject(scaleObject);
  633. return function (d) {
  634. var value = _getAttrValue(d, scaleObject.accessor0);
  635. return scaleFn(_isDefined(value) ? value : baseValue);
  636. };
  637. }
  638. return null;
  639. }
  640. /**
  641. * Tries to get the string|number value of the attr and falls back to
  642. * a fallback property in case if the value is a scale.
  643. * @param {Object} props Series props.
  644. * @param {string} attr Property name.
  645. * @returns {*} Function or value.
  646. */
  647. function getAttributeValue(props, attr) {
  648. var scaleObject = getScaleObjectFromProps(props, attr);
  649. if (scaleObject) {
  650. if (!scaleObject.isValue && props['_' + attr + 'Value'] === undefined) {
  651. (0, _reactUtils.warning)('[React-vis] Cannot use data defined ' + attr + ' for this ' + 'series type. Using fallback value instead.');
  652. }
  653. return props['_' + attr + 'Value'] || scaleObject.range[0];
  654. }
  655. return null;
  656. }
  657. /**
  658. * Get prop types by the attribute.
  659. * @param {string} attr Attribute.
  660. * @returns {Object} Object of xDomain, xRange, xType, xDistance and _xValue,
  661. * where x is an attribute passed to the function.
  662. */
  663. function getScalePropTypesByAttribute(attr) {
  664. var _ref2;
  665. return _ref2 = {}, _defineProperty(_ref2, '_' + attr + 'Value', _propTypes2.default.any), _defineProperty(_ref2, attr + 'Domain', _propTypes2.default.array), _defineProperty(_ref2, 'get' + toTitleCase(attr), _propTypes2.default.func), _defineProperty(_ref2, 'get' + toTitleCase(attr) + '0', _propTypes2.default.func), _defineProperty(_ref2, attr + 'Range', _propTypes2.default.array), _defineProperty(_ref2, attr + 'Type', _propTypes2.default.oneOf(Object.keys(SCALE_FUNCTIONS))), _defineProperty(_ref2, attr + 'Distance', _propTypes2.default.number), _defineProperty(_ref2, attr + 'BaseValue', _propTypes2.default.any), _ref2;
  666. }
  667. /**
  668. * Extract the list of scale properties from the entire props object.
  669. * @param {Object} props Props.
  670. * @param {Array<String>} attributes Array of attributes for the given
  671. * components (for instance, `['x', 'y', 'color']`).
  672. * @returns {Object} Collected props.
  673. */
  674. function extractScalePropsFromProps(props, attributes) {
  675. var result = {};
  676. Object.keys(props).forEach(function (key) {
  677. // this filtering is critical for extracting the correct accessors!
  678. var attr = attributes.find(function (a) {
  679. // width
  680. var isPlainSet = key.indexOf(a) === 0;
  681. // Ex: _data
  682. var isUnderscoreSet = key.indexOf('_' + a) === 0;
  683. // EX: getX
  684. var usesGet = key.indexOf('get' + toTitleCase(a)) === 0;
  685. return isPlainSet || isUnderscoreSet || usesGet;
  686. });
  687. if (!attr) {
  688. return;
  689. }
  690. result[key] = props[key];
  691. });
  692. return result;
  693. }
  694. /**
  695. * Extract the missing scale props from the given data and return them as
  696. * an object.
  697. * @param {Object} props Props.
  698. * @param {Array} data Array of all data.
  699. * @param {Array<String>} attributes Array of attributes for the given
  700. * components (for instance, `['x', 'y', 'color']`).
  701. * @returns {Object} Collected props.
  702. */
  703. function getMissingScaleProps(props, data, attributes) {
  704. var result = {};
  705. // Make sure that the domain is set pad it if specified
  706. attributes.forEach(function (attr) {
  707. if (!props['get' + toTitleCase(attr)]) {
  708. result['get' + toTitleCase(attr)] = function (d) {
  709. return d[attr];
  710. };
  711. }
  712. if (!props['get' + toTitleCase(attr) + '0']) {
  713. result['get' + toTitleCase(attr) + '0'] = function (d) {
  714. return d[attr + '0'];
  715. };
  716. }
  717. if (!props[attr + 'Domain']) {
  718. result[attr + 'Domain'] = getDomainByAccessor(data, props['get' + toTitleCase(attr)] || result['get' + toTitleCase(attr)], props['get' + toTitleCase(attr) + '0'] || result['get' + toTitleCase(attr) + '0'], props[attr + 'Type']);
  719. if (props[attr + 'Padding']) {
  720. result[attr + 'Domain'] = _padDomain(result[attr + 'Domain'], props[attr + 'Padding']);
  721. }
  722. }
  723. });
  724. return result;
  725. }
  726. /**
  727. * Return a d3 scale that returns the literal value that was given to it
  728. * @returns {function} literal scale.
  729. */
  730. function literalScale(defaultValue) {
  731. function scale(d) {
  732. if (d === undefined) {
  733. return defaultValue;
  734. }
  735. return d;
  736. }
  737. function response() {
  738. return scale;
  739. }
  740. scale.domain = response;
  741. scale.range = response;
  742. scale.unknown = response;
  743. scale.copy = response;
  744. return scale;
  745. }
  746. function getFontColorFromBackground(background) {
  747. if (background) {
  748. return (0, _d3Color.hsl)(background).l > 0.57 ? '#222' : '#fff';
  749. }
  750. return null;
  751. }
  752. /**
  753. * Creates fallback values for series from scales defined at XYPlot level.
  754. * @param {Object} props Props of the XYPlot object.
  755. * @param {Array<Object>} children Array of components, children of XYPlot
  756. * @returns {Array<Object>} Collected props.
  757. */
  758. function getXYPlotValues(props, children) {
  759. var XYPlotScales = XYPLOT_ATTR.reduce(function (prev, attr) {
  760. var domain = props[attr + 'Domain'],
  761. range = props[attr + 'Range'],
  762. type = props[attr + 'Type'];
  763. if (domain && range && type) {
  764. return _extends({}, prev, _defineProperty({}, attr, SCALE_FUNCTIONS[type]().domain(domain).range(range)));
  765. }
  766. return prev;
  767. }, {});
  768. return children.map(function (child) {
  769. return XYPLOT_ATTR.reduce(function (prev, attr) {
  770. if (child.props && child.props[attr] !== undefined) {
  771. var scaleInput = child.props[attr];
  772. var scale = XYPlotScales[attr];
  773. var fallbackValue = scale ? scale(scaleInput) : scaleInput;
  774. return _extends({}, prev, _defineProperty({}, '_' + attr + 'Value', fallbackValue));
  775. }
  776. return prev;
  777. }, {});
  778. });
  779. }
  780. var OPTIONAL_SCALE_PROPS = ['Padding'];
  781. var OPTIONAL_SCALE_PROPS_REGS = OPTIONAL_SCALE_PROPS.map(function (str) {
  782. return new RegExp(str + '$', 'i');
  783. });
  784. /**
  785. * Get the list of optional scale-related settings for XYPlot
  786. * mostly just used to find padding properties
  787. * @param {Object} props Object of props.
  788. * @returns {Object} Optional Props.
  789. * @private
  790. */
  791. function getOptionalScaleProps(props) {
  792. return Object.keys(props).reduce(function (acc, prop) {
  793. var propIsNotOptional = OPTIONAL_SCALE_PROPS_REGS.every(function (reg) {
  794. return !prop.match(reg);
  795. });
  796. if (propIsNotOptional) {
  797. return acc;
  798. }
  799. acc[prop] = props[prop];
  800. return acc;
  801. }, {});
  802. }
  803. exports.default = {
  804. extractScalePropsFromProps: extractScalePropsFromProps,
  805. getAttributeScale: getAttributeScale,
  806. getAttributeFunctor: getAttributeFunctor,
  807. getAttr0Functor: getAttr0Functor,
  808. getAttributeValue: getAttributeValue,
  809. getDomainByAccessor: getDomainByAccessor,
  810. getFontColorFromBackground: getFontColorFromBackground,
  811. getMissingScaleProps: getMissingScaleProps,
  812. getOptionalScaleProps: getOptionalScaleProps,
  813. getScaleObjectFromProps: getScaleObjectFromProps,
  814. getScalePropTypesByAttribute: getScalePropTypesByAttribute,
  815. getXYPlotValues: getXYPlotValues,
  816. literalScale: literalScale
  817. };