gauge.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. var __rest = (this && this.__rest) || function (s, e) {
  2. var t = {};
  3. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  4. t[p] = s[p];
  5. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  6. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  7. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  8. t[p[i]] = s[p[i]];
  9. }
  10. return t;
  11. };
  12. import { deepMix } from '@antv/util';
  13. import { Group } from '@antv/g';
  14. import { filterPrefixObject, isUnset, subObject } from '../utils/helper';
  15. import { getTransformOptions } from '../utils/coordinate';
  16. import { Radial } from '../coordinate';
  17. import { applyStyle, getOrigin } from '../shape/utils';
  18. import { select } from '../utils/selection';
  19. function dataTransform(data, scale) {
  20. const { name = 'score', target, total, percent, thresholds = [] } = data;
  21. const _target = percent || target;
  22. const _total = percent ? 1 : total;
  23. const newScale = Object.assign({ y: {
  24. domain: [0, _total],
  25. } }, scale);
  26. if (!thresholds.length) {
  27. return {
  28. targetData: [{ x: name, y: _target, color: 'target' }],
  29. totalData: [
  30. { x: name, y: _target, color: 'target' },
  31. { x: name, y: _total - _target, color: 'total' },
  32. ],
  33. target: _target,
  34. total: _total,
  35. scale: newScale,
  36. };
  37. }
  38. return {
  39. targetData: [{ x: name, y: _target, color: 'target' }],
  40. totalData: thresholds.map((d, i) => ({
  41. x: name,
  42. y: i >= 1 ? d - thresholds[i - 1] : d,
  43. color: i,
  44. })),
  45. target: _target,
  46. total: _total,
  47. scale: newScale,
  48. };
  49. }
  50. function getTextContent(textStyle, { target, total }) {
  51. const { content } = textStyle;
  52. return content ? content(target, total) : target.toString();
  53. }
  54. const indicatorShape = (options) => {
  55. const { shape, radius } = options, style = __rest(options, ["shape", "radius"]);
  56. const pointerStyle = subObject(style, 'pointer');
  57. const pinStyle = subObject(style, 'pin');
  58. const { shape: pointerShape } = pointerStyle, resPointerStyle = __rest(pointerStyle, ["shape"]);
  59. const { shape: pinShape } = pinStyle, resPinStyle = __rest(pinStyle, ["shape"]);
  60. return (points, value, coordinate, theme) => {
  61. // Invert points.
  62. const invertedPoints = points.map((p) => coordinate.invert(p));
  63. // Get new coordinate.
  64. const [startAngle, endAngle, innerRadius] = getTransformOptions(coordinate, 'polar');
  65. const newCoordinate = coordinate.clone();
  66. const { color: stroke } = value;
  67. const newTransformations = Radial({
  68. startAngle,
  69. endAngle,
  70. innerRadius,
  71. outerRadius: radius,
  72. });
  73. newTransformations.push(['cartesian']);
  74. newCoordinate.update({
  75. transformations: newTransformations,
  76. });
  77. const newPoints = invertedPoints.map((p) => newCoordinate.map(p));
  78. const [x, y] = getOrigin(newPoints);
  79. const [cx, cy] = coordinate.getCenter();
  80. const pointerAttrs = Object.assign(Object.assign({ x1: x, y1: y, x2: cx, y2: cy, stroke }, resPointerStyle), style);
  81. const pinAttrs = Object.assign(Object.assign({ cx,
  82. cy,
  83. stroke }, resPinStyle), style);
  84. const indicatorGroup = select(new Group());
  85. if (!isUnset(pointerShape)) {
  86. typeof pointerShape === 'function'
  87. ? indicatorGroup.append(() => pointerShape(newPoints, value, newCoordinate, theme))
  88. : indicatorGroup.append('line').call(applyStyle, pointerAttrs).node();
  89. }
  90. if (!isUnset(pinShape)) {
  91. typeof pinShape === 'function'
  92. ? indicatorGroup.append(() => pinShape(newPoints, value, newCoordinate, theme))
  93. : indicatorGroup.append('circle').call(applyStyle, pinAttrs).node();
  94. }
  95. return indicatorGroup.node();
  96. };
  97. };
  98. export const Gauge = (options) => {
  99. const DEFAULT_OPTIONS = {
  100. coordinate: {
  101. type: 'radial',
  102. innerRadius: 0.9,
  103. outerRadius: 1,
  104. startAngle: (-11 / 10) * Math.PI,
  105. endAngle: (1 / 10) * Math.PI,
  106. },
  107. axis: {
  108. x: false,
  109. },
  110. legend: false,
  111. tooltip: false,
  112. encode: {
  113. x: 'x',
  114. y: 'y',
  115. color: 'color',
  116. },
  117. scale: {
  118. color: {
  119. range: ['#30BF78', '#D0D0D0'],
  120. },
  121. },
  122. };
  123. const DEFAULT_INDICATOR_OPTIONS = {
  124. style: {
  125. shape: indicatorShape,
  126. lineWidth: 4,
  127. pointerLineCap: 'round',
  128. pinR: 10,
  129. pinFill: '#fff',
  130. radius: 0.6,
  131. },
  132. };
  133. const DEFAULT_TEXT_OPTIONS = {
  134. type: 'text',
  135. style: {
  136. x: '50%',
  137. y: '60%',
  138. textAlign: 'center',
  139. textBaseline: 'middle',
  140. fontSize: 20,
  141. fontWeight: 800,
  142. fill: '#888',
  143. },
  144. };
  145. return () => {
  146. const { data = {}, scale = {}, style = {}, animate = {}, transform = [] } = options, resOptions = __rest(options, ["data", "scale", "style", "animate", "transform"]);
  147. const { targetData, totalData, target, total, scale: newScale, } = dataTransform(data, scale);
  148. const textStyle = subObject(style, 'text');
  149. // pointer + pin
  150. const indicatorStyle = filterPrefixObject(style, ['pointer', 'pin']);
  151. return [
  152. deepMix({}, DEFAULT_OPTIONS, Object.assign({ type: 'interval', transform: [{ type: 'stackY' }], data: totalData, scale: newScale, style: subObject(style, 'arc'), animate: typeof animate === 'object' ? subObject(animate, 'arc') : animate }, resOptions)),
  153. deepMix({}, DEFAULT_OPTIONS, DEFAULT_INDICATOR_OPTIONS, Object.assign({ type: 'point', data: targetData, scale: newScale, style: indicatorStyle, animate: typeof animate === 'object'
  154. ? subObject(animate, 'indicator')
  155. : animate }, resOptions)),
  156. deepMix({}, DEFAULT_TEXT_OPTIONS, {
  157. style: Object.assign({ text: getTextContent(textStyle, { target, total }) }, textStyle),
  158. animate: typeof animate === 'object' ? subObject(animate, 'text') : animate,
  159. }),
  160. ];
  161. };
  162. };
  163. Gauge.props = {};
  164. //# sourceMappingURL=gauge.js.map