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

239 строки
7.8 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. // Copyright (c) 2016 - 2017 Uber Technologies, Inc.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. import React from 'react';
  22. import PropTypes from 'prop-types';
  23. import { pie as pieBuilder } from 'd3-shape';
  24. import { AnimationPropType } from '../animation';
  25. import ArcSeries from '../plot/series/arc-series';
  26. import LabelSeries from '../plot/series/label-series';
  27. import XYPlot from '../plot/xy-plot';
  28. import { DISCRETE_COLOR_RANGE } from '../theme';
  29. import { MarginPropType, getRadialLayoutMargin } from '../utils/chart-utils';
  30. import { getRadialDomain } from '../utils/series-utils';
  31. var predefinedClassName = 'rv-radial-chart';
  32. var DEFAULT_RADIUS_MARGIN = 15;
  33. /**
  34. * Create the list of wedges to render.
  35. * @param {Object} props
  36. props.data {Object} - tree structured data (each node has a name anc an array of children)
  37. * @returns {Array} Array of nodes.
  38. */
  39. function getWedgesToRender(_ref) {
  40. var data = _ref.data,
  41. getAngle = _ref.getAngle;
  42. var pie = pieBuilder().sort(null).value(getAngle);
  43. var pieData = pie(data).reverse();
  44. return pieData.map(function (row, index) {
  45. return _extends({}, row.data, {
  46. angle0: row.startAngle,
  47. angle: row.endAngle,
  48. radius0: row.data.innerRadius || 0,
  49. radius: row.data.radius || 1,
  50. color: row.data.color || index
  51. });
  52. });
  53. }
  54. function generateLabels(mappedData, accessors) {
  55. var labelsRadiusMultiplier = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1.1;
  56. var getLabel = accessors.getLabel,
  57. getSubLabel = accessors.getSubLabel;
  58. return mappedData.reduce(function (res, row) {
  59. var angle = row.angle,
  60. angle0 = row.angle0,
  61. radius = row.radius;
  62. var centeredAngle = (angle + angle0) / 2;
  63. // unfortunate, but true fact: d3 starts its radians at 12 oclock rather than 3
  64. // and move clockwise rather than counter clockwise. why why why!
  65. var updatedAngle = -1 * centeredAngle + Math.PI / 2;
  66. var newLabels = [];
  67. if (getLabel(row)) {
  68. newLabels.push({
  69. angle: updatedAngle,
  70. radius: radius * labelsRadiusMultiplier,
  71. label: getLabel(row)
  72. });
  73. }
  74. if (getSubLabel(row)) {
  75. newLabels.push({
  76. angle: updatedAngle,
  77. radius: radius * labelsRadiusMultiplier,
  78. label: getSubLabel(row),
  79. style: { fontSize: 10 },
  80. yOffset: 12
  81. });
  82. }
  83. return res.concat(newLabels);
  84. }, []);
  85. // could add force direction here to make sure the labels dont overlap
  86. }
  87. /**
  88. * Get the max radius so the chart can extend to the margin.
  89. * @param {Number} width - container width
  90. * @param {Number} height - container height
  91. * @return {Number} radius
  92. */
  93. function getMaxRadius(width, height) {
  94. return Math.min(width, height) / 2 - DEFAULT_RADIUS_MARGIN;
  95. }
  96. function RadialChart(props) {
  97. var animation = props.animation,
  98. className = props.className,
  99. children = props.children,
  100. colorType = props.colorType,
  101. data = props.data,
  102. getAngle = props.getAngle,
  103. getLabel = props.getLabel,
  104. getSubLabel = props.getSubLabel,
  105. height = props.height,
  106. hideRootNode = props.hideRootNode,
  107. innerRadius = props.innerRadius,
  108. labelsAboveChildren = props.labelsAboveChildren,
  109. labelsRadiusMultiplier = props.labelsRadiusMultiplier,
  110. labelsStyle = props.labelsStyle,
  111. margin = props.margin,
  112. onMouseLeave = props.onMouseLeave,
  113. onMouseEnter = props.onMouseEnter,
  114. radius = props.radius,
  115. showLabels = props.showLabels,
  116. style = props.style,
  117. width = props.width;
  118. var mappedData = getWedgesToRender({
  119. data: data,
  120. height: height,
  121. hideRootNode: hideRootNode,
  122. width: width,
  123. getAngle: getAngle
  124. });
  125. var radialDomain = getRadialDomain(mappedData);
  126. var arcProps = _extends({
  127. colorType: colorType
  128. }, props, {
  129. animation: animation,
  130. radiusDomain: [0, radialDomain],
  131. data: mappedData,
  132. radiusNoFallBack: true,
  133. style: style,
  134. arcClassName: 'rv-radial-chart__series--pie__slice'
  135. });
  136. if (radius) {
  137. arcProps.radiusDomain = [0, 1];
  138. arcProps.radiusRange = [innerRadius || 0, radius];
  139. arcProps.radiusType = 'linear';
  140. }
  141. var maxRadius = radius ? radius : getMaxRadius(width, height);
  142. var defaultMargin = getRadialLayoutMargin(width, height, maxRadius);
  143. var labels = generateLabels(mappedData, {
  144. getLabel: getLabel,
  145. getSubLabel: getSubLabel
  146. }, labelsRadiusMultiplier);
  147. return React.createElement(
  148. XYPlot,
  149. {
  150. height: height,
  151. width: width,
  152. margin: _extends({}, margin, defaultMargin),
  153. className: className + ' ' + predefinedClassName,
  154. onMouseLeave: onMouseLeave,
  155. onMouseEnter: onMouseEnter,
  156. xDomain: [-radialDomain, radialDomain],
  157. yDomain: [-radialDomain, radialDomain]
  158. },
  159. React.createElement(ArcSeries, _extends({}, arcProps, { getAngle: function getAngle(d) {
  160. return d.angle;
  161. } })),
  162. showLabels && !labelsAboveChildren && React.createElement(LabelSeries, { data: labels, style: labelsStyle }),
  163. children,
  164. showLabels && labelsAboveChildren && React.createElement(LabelSeries, { data: labels, style: labelsStyle })
  165. );
  166. }
  167. RadialChart.displayName = 'RadialChart';
  168. RadialChart.propTypes = {
  169. animation: AnimationPropType,
  170. className: PropTypes.string,
  171. colorType: PropTypes.string,
  172. data: PropTypes.arrayOf(PropTypes.shape({
  173. angle: PropTypes.number,
  174. className: PropTypes.string,
  175. label: PropTypes.string,
  176. radius: PropTypes.number,
  177. style: PropTypes.object
  178. })).isRequired,
  179. getAngle: PropTypes.func,
  180. getAngle0: PropTypes.func,
  181. padAngle: PropTypes.oneOfType([PropTypes.func, PropTypes.number]),
  182. getRadius: PropTypes.func,
  183. getRadius0: PropTypes.func,
  184. getLabel: PropTypes.func,
  185. height: PropTypes.number.isRequired,
  186. labelsAboveChildren: PropTypes.bool,
  187. labelsStyle: PropTypes.object,
  188. margin: MarginPropType,
  189. onValueClick: PropTypes.func,
  190. onValueMouseOver: PropTypes.func,
  191. onValueMouseOut: PropTypes.func,
  192. showLabels: PropTypes.bool,
  193. style: PropTypes.object,
  194. subLabel: PropTypes.func,
  195. width: PropTypes.number.isRequired
  196. };
  197. RadialChart.defaultProps = {
  198. className: '',
  199. colorType: 'category',
  200. colorRange: DISCRETE_COLOR_RANGE,
  201. padAngle: 0,
  202. getAngle: function getAngle(d) {
  203. return d.angle;
  204. },
  205. getAngle0: function getAngle0(d) {
  206. return d.angle0;
  207. },
  208. getRadius: function getRadius(d) {
  209. return d.radius;
  210. },
  211. getRadius0: function getRadius0(d) {
  212. return d.radius0;
  213. },
  214. getLabel: function getLabel(d) {
  215. return d.label;
  216. },
  217. getSubLabel: function getSubLabel(d) {
  218. return d.subLabel;
  219. }
  220. };
  221. export default RadialChart;