Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

253 строки
9.6 KiB

  1. 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; };
  2. 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; }
  3. // Copyright (c) 2016 - 2017 Uber Technologies, Inc.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. import React from 'react';
  23. import AbstractSeries from '../plot/series/abstract-series';
  24. import { DISCRETE_COLOR_RANGE, DEFAULT_OPACITY } from '../theme';
  25. /**
  26. * Check if the component is series or not.
  27. * @param {React.Component} child Component.
  28. * @returns {boolean} True if the child is series, false otherwise.
  29. */
  30. export function isSeriesChild(child) {
  31. var prototype = child.type.prototype;
  32. return prototype instanceof AbstractSeries;
  33. }
  34. /**
  35. * Get all series from the 'children' object of the component.
  36. * @param {Object} children Children.
  37. * @returns {Array} Array of children.
  38. */
  39. export function getSeriesChildren(children) {
  40. return React.Children.toArray(children).filter(function (child) {
  41. return child && isSeriesChild(child);
  42. });
  43. }
  44. /**
  45. * Collect the map of repetitions of the series type for all children.
  46. * @param {Array} children Array of children.
  47. * @returns {{}} Map of repetitions where sameTypeTotal is the total amount and
  48. * sameTypeIndex is always 0.
  49. */
  50. function collectSeriesTypesInfo(children) {
  51. var result = {};
  52. children.filter(isSeriesChild).forEach(function (child) {
  53. var displayName = child.type.displayName;
  54. var cluster = child.props.cluster;
  55. if (!result[displayName]) {
  56. result[displayName] = {
  57. sameTypeTotal: 0,
  58. sameTypeIndex: 0,
  59. clusters: new Set()
  60. };
  61. }
  62. result[displayName].clusters.add(cluster);
  63. result[displayName].sameTypeTotal++;
  64. });
  65. return result;
  66. }
  67. /**
  68. * Check series to see if it has angular data that needs to be converted
  69. * @param {Array} data - an array of objects to check
  70. * @returns {Boolean} whether or not this series contains polar configuration
  71. */
  72. function seriesHasAngleRadius() {
  73. var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  74. if (!data) {
  75. return false;
  76. }
  77. return data.some(function (row) {
  78. return row.radius && row.angle;
  79. });
  80. }
  81. /**
  82. * Possibly convert polar coordinates to x/y for computing domain
  83. * @param {Array} data - an array of objects to check
  84. * @param {String} attr - the property being checked
  85. * @returns {Boolean} whether or not this series contains polar configuration
  86. */
  87. function prepareData(data) {
  88. if (!seriesHasAngleRadius(data)) {
  89. return data;
  90. }
  91. return data.map(function (row) {
  92. return _extends({}, row, {
  93. x: row.radius * Math.cos(row.angle),
  94. y: row.radius * Math.sin(row.angle)
  95. });
  96. });
  97. }
  98. /**
  99. * Collect the stacked data for all children in use. If the children don't have
  100. * the data (e.g. the child is invalid series or something else), then the child
  101. * is skipped.
  102. * Each next value of attr is equal to the previous value plus the difference
  103. * between attr0 and attr.
  104. * @param {Array} children Array of children.
  105. * @param {string} attr Attribute to stack by.
  106. * @returns {Array} New array of children for the series.
  107. */
  108. export function getStackedData(children, attr) {
  109. var areSomeSeriesStacked = children.some(function (series) {
  110. return series && series.props.stack;
  111. });
  112. // It stores the last segment position added to each bar, separated by cluster.
  113. var latestAttrPositions = {};
  114. return children.reduce(function (accumulator, series, seriesIndex) {
  115. // Skip the children that are not series (e.g. don't have any data).
  116. if (!series) {
  117. accumulator.push(null);
  118. return accumulator;
  119. }
  120. var seriesType = series.type.displayName;
  121. var _series$props = series.props,
  122. data = _series$props.data,
  123. _series$props$cluster = _series$props.cluster,
  124. cluster = _series$props$cluster === undefined ? 'default' : _series$props$cluster,
  125. stack = _series$props.stack;
  126. var preppedData = prepareData(data, attr);
  127. if (!attr || !preppedData || !preppedData.length || areSomeSeriesStacked && !stack) {
  128. accumulator.push(preppedData);
  129. return accumulator;
  130. }
  131. var attr0 = attr + '0';
  132. var baseAttr = attr === 'y' ? 'x' : 'y';
  133. accumulator.push(preppedData.map(function (d, dIndex) {
  134. var _extends2, _latestAttrPositions$2;
  135. if (!latestAttrPositions[cluster]) {
  136. latestAttrPositions[cluster] = {};
  137. }
  138. if (!latestAttrPositions[cluster][seriesType]) {
  139. latestAttrPositions[cluster][seriesType] = {};
  140. }
  141. var prevD = latestAttrPositions[cluster][seriesType][d[baseAttr]];
  142. // It is the first segment of a bar.
  143. if (!prevD) {
  144. var _latestAttrPositions$;
  145. latestAttrPositions[cluster][seriesType][d[baseAttr]] = (_latestAttrPositions$ = {}, _defineProperty(_latestAttrPositions$, attr0, d[attr0]), _defineProperty(_latestAttrPositions$, attr, d[attr]), _latestAttrPositions$);
  146. return _extends({}, d);
  147. }
  148. // Calculate the position of the next segment in a bar.
  149. var nextD = _extends({}, d, (_extends2 = {}, _defineProperty(_extends2, attr0, prevD[attr]), _defineProperty(_extends2, attr, prevD[attr] + d[attr] - (d[attr0] || 0)), _extends2));
  150. latestAttrPositions[cluster][seriesType][d[baseAttr]] = (_latestAttrPositions$2 = {}, _defineProperty(_latestAttrPositions$2, attr0, nextD[attr0]), _defineProperty(_latestAttrPositions$2, attr, nextD[attr]), _latestAttrPositions$2);
  151. return nextD;
  152. }));
  153. return accumulator;
  154. }, []);
  155. }
  156. /**
  157. * Get the list of series props for a child.
  158. * @param {Array} children Array of all children.
  159. * @returns {Array} Array of series props for each child. If a child is not a
  160. * series, than it's undefined.
  161. */
  162. export function getSeriesPropsFromChildren(children) {
  163. var result = [];
  164. var seriesTypesInfo = collectSeriesTypesInfo(children);
  165. var seriesIndex = 0;
  166. var _opacityValue = DEFAULT_OPACITY;
  167. children.forEach(function (child) {
  168. var props = void 0;
  169. if (isSeriesChild(child)) {
  170. var seriesTypeInfo = seriesTypesInfo[child.type.displayName];
  171. var _colorValue = DISCRETE_COLOR_RANGE[seriesIndex % DISCRETE_COLOR_RANGE.length];
  172. props = _extends({}, seriesTypeInfo, {
  173. seriesIndex: seriesIndex,
  174. _colorValue: _colorValue,
  175. _opacityValue: _opacityValue
  176. });
  177. seriesTypeInfo.sameTypeIndex++;
  178. seriesIndex++;
  179. if (child.props.cluster) {
  180. props.cluster = child.props.cluster;
  181. // Using Array.from() so we can use .indexOf
  182. props.clusters = Array.from(seriesTypeInfo.clusters);
  183. props.sameTypeTotal = props.clusters.length;
  184. props.sameTypeIndex = props.clusters.indexOf(child.props.cluster);
  185. }
  186. }
  187. result.push(props);
  188. });
  189. return result;
  190. }
  191. /**
  192. * Find the max radius value from the nodes to be rendered after they have been
  193. * transformed into an array
  194. * @param {Array} data - the tree data after it has been broken into a iterable
  195. * it is an array of objects!
  196. * @returns {number} the maximum value in coordinates for the radial variable
  197. */
  198. export function getRadialDomain(data) {
  199. return data.reduce(function (res, row) {
  200. return Math.max(row.radius, res);
  201. }, 0);
  202. }
  203. export var ANIMATED_SERIES_PROPS = ['xRange', 'xDomain', 'x', 'yRange', 'yDomain', 'y', 'colorRange', 'colorDomain', 'color', 'opacityRange', 'opacityDomain', 'opacity', 'strokeRange', 'strokeDomain', 'stroke', 'fillRange', 'fillDomain', 'fill', 'width', 'height', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'data', 'angleDomain', 'angleRange', 'angle', 'radiusDomain', 'radiusRange', 'radius', 'innerRadiusDomain', 'innerRadiusRange', 'innerRadius'];
  204. export function getStackParams(props) {
  205. var _stackBy = props._stackBy,
  206. valuePosAttr = props.valuePosAttr,
  207. cluster = props.cluster;
  208. var _props$sameTypeTotal = props.sameTypeTotal,
  209. sameTypeTotal = _props$sameTypeTotal === undefined ? 1 : _props$sameTypeTotal,
  210. _props$sameTypeIndex = props.sameTypeIndex,
  211. sameTypeIndex = _props$sameTypeIndex === undefined ? 0 : _props$sameTypeIndex;
  212. // If bars are stacked, but not clustering, override `sameTypeTotal` and
  213. // `sameTypeIndex` such that bars are stacked and not staggered.
  214. if (_stackBy === valuePosAttr && !cluster) {
  215. sameTypeTotal = 1;
  216. sameTypeIndex = 0;
  217. }
  218. return { sameTypeTotal: sameTypeTotal, sameTypeIndex: sameTypeIndex };
  219. }