curve.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 { line, lineRadial } from 'd3-shape';
  13. import { Path } from '@antv/g';
  14. import { isPolar } from '../../utils/coordinate';
  15. import { select } from '../../utils/selection';
  16. import { applyStyle, computeGradient, getShapeTheme, getTransform, } from '../utils';
  17. import { createElement } from '../../utils/createElement';
  18. import { subObject } from '../../utils/helper';
  19. import { angleWithQuadrant, dist, sub } from '../../utils/vector';
  20. const DoublePath = createElement((g) => {
  21. const { d1, d2, style1, style2 } = g.attributes;
  22. select(g)
  23. .maybeAppend('line', () => new Path({}))
  24. .style('d', d1)
  25. .call(applyStyle, style1);
  26. select(g)
  27. .maybeAppend('line1', () => new Path({}))
  28. .style('d', d2)
  29. .call(applyStyle, style2);
  30. });
  31. /**
  32. * Given a points sequence, split it into an array of defined points
  33. * and an array of undefined segments.
  34. *
  35. * Input - [[1, 2], [3, 4], [null, null], [null, null], [5, 6], [null, null], [7, 8]]
  36. * Output
  37. * - [[1, 2], [3, 4], [5, 6], [7, 8]]
  38. * - [
  39. * [[3, 4], [5, 6]],
  40. * [[5, 6], [7, 8]]
  41. * ]
  42. */
  43. function segmentation(points, defined) {
  44. const definedPoints = [];
  45. const segments = [];
  46. let m = false; // Is in a undefined sequence.
  47. let dp = null; // The previous defined point.
  48. for (const p of points) {
  49. // If current point is a undefined point,
  50. // enter a undefined sequence.
  51. if (!defined(p[0]) || !defined(p[1]))
  52. m = true;
  53. else {
  54. definedPoints.push(p);
  55. // If current point is a defined point,
  56. // and is in a undefined sequence, save
  57. // the two closest defined points as this
  58. // undefined sequence and exit it.
  59. if (m) {
  60. m = false;
  61. segments.push([dp, p]);
  62. }
  63. // Update the previous defined point.
  64. dp = p;
  65. }
  66. }
  67. return [definedPoints, segments];
  68. }
  69. export const Curve = (options) => {
  70. const { curve, gradient = false,
  71. // The color for each segment.
  72. gradientColor = 'between', defined = (d) => !Number.isNaN(d) && d !== undefined && d !== null, connect: connectNulls = false } = options, style = __rest(options, ["curve", "gradient", "gradientColor", "defined", "connect"]);
  73. return (P, value, coordinate, theme) => {
  74. // Compute styles.
  75. const { mark, shape, defaultShape } = value;
  76. const _a = getShapeTheme(theme, mark, shape, defaultShape), { defaultColor, lineWidth: defaultSize } = _a, defaults = __rest(_a, ["defaultColor", "lineWidth"]);
  77. const { color = defaultColor, size = defaultSize, seriesColor: sc, seriesX: sx, seriesY: sy, } = value;
  78. const stroke = gradient && sc
  79. ? computeGradient(sc, sx, sy, gradient, gradientColor)
  80. : color;
  81. const transform = getTransform(coordinate, value);
  82. const finalStyle = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, defaults), (stroke && { stroke })), (size && { lineWidth: size })), (transform && { transform })), style);
  83. // Compute points and segments.
  84. let linePath;
  85. if (isPolar(coordinate)) {
  86. const center = coordinate.getCenter();
  87. linePath = (points) => lineRadial()
  88. .angle((_, idx) => angleWithQuadrant(sub(points[idx], center)))
  89. .radius((_, idx) => dist(points[idx], center))
  90. .defined(([x, y]) => defined(x) && defined(y))
  91. .curve(curve)(points);
  92. }
  93. else {
  94. linePath = line()
  95. .x((d) => d[0])
  96. .y((d) => d[1])
  97. .defined(([x, y]) => defined(x) && defined(y))
  98. .curve(curve);
  99. }
  100. const [DP, MS] = segmentation(P, defined);
  101. const connectStyle = subObject(finalStyle, 'connect');
  102. const missing = !!MS.length;
  103. // Draw one path of connected defined points.
  104. if (!missing || (connectNulls && !Object.keys(connectStyle).length)) {
  105. return select(new Path({}))
  106. .style('d', linePath(DP) || [])
  107. .call(applyStyle, finalStyle)
  108. .node();
  109. }
  110. // Draw one path of unconnected defined points.
  111. if (missing && !connectNulls) {
  112. return select(new Path({}))
  113. .style('d', linePath(P))
  114. .call(applyStyle, finalStyle)
  115. .node();
  116. }
  117. // Draw two path.
  118. // One for unconnected defined points.
  119. // One for connected segments.
  120. const connectPath = (segments) => segments.map(linePath).join(',');
  121. return select(new DoublePath())
  122. .style('style1', Object.assign(Object.assign({}, finalStyle), connectStyle))
  123. .style('style2', finalStyle)
  124. .style('d1', connectPath(MS))
  125. .style('d2', linePath(P))
  126. .node();
  127. };
  128. };
  129. Curve.props = {
  130. defaultMarker: 'smooth',
  131. defaultEnterAnimation: 'fadeIn',
  132. defaultUpdateAnimation: 'morphing',
  133. defaultExitAnimation: 'fadeOut',
  134. };
  135. //# sourceMappingURL=curve.js.map