line.js 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { group } from 'd3-array';
  2. import { isParallel } from '../utils/coordinate';
  3. import { baseGeometryChannels, basePostInference, basePreInference, tooltip1d, tooltipXd, } from './utils';
  4. const line = (index, scale, value, coordinate) => {
  5. var _a, _b;
  6. const { series: S, x: X, y: Y } = value;
  7. const { x, y } = scale;
  8. // Because x and y channel is not strictly required in Line.props,
  9. // it should throw error with empty x or y channels.
  10. if (X === undefined || Y === undefined) {
  11. throw new Error('Missing encode for x or y channel.');
  12. }
  13. // Group data into series.
  14. // There is only one series without specified series encode.
  15. const series = S ? Array.from(group(index, (i) => S[i]).values()) : [index];
  16. const I = series.map((group) => group[0]).filter((i) => i !== undefined);
  17. // A group of data corresponds to one line.
  18. const xoffset = (((_a = x === null || x === void 0 ? void 0 : x.getBandWidth) === null || _a === void 0 ? void 0 : _a.call(x)) || 0) / 2;
  19. const yoffset = (((_b = y === null || y === void 0 ? void 0 : y.getBandWidth) === null || _b === void 0 ? void 0 : _b.call(y)) || 0) / 2;
  20. const P = Array.from(series, (I) => {
  21. return I.map((i) => coordinate.map([+X[i] + xoffset, +Y[i] + yoffset]));
  22. });
  23. return [I, P, series];
  24. };
  25. const parallel = (index, scale, value, coordinate) => {
  26. // Extract all value for position[number] channels.
  27. const PV = Object.entries(value)
  28. .filter(([key]) => key.startsWith('position'))
  29. .map(([, value]) => value);
  30. // Because position channel is not strictly required in Line.props,
  31. // it should throw error with empty position values.
  32. if (PV.length === 0) {
  33. throw new Error('Missing encode for position channel.');
  34. }
  35. // One data corresponds to one line.
  36. const P = Array.from(index, (i) => {
  37. // Transform high dimension vector to a list of two-dimension vectors.
  38. // [a, b, c] -> [d, e, f, g, h, i]
  39. const vector = PV.map((pv) => +pv[i]);
  40. const vectors = coordinate.map(vector);
  41. // Two-dimension vectors are stored in a flat array, so extract them.
  42. // [d, e, f, g, h, i] -> [d, e], [f, g], [h, i]
  43. const points = [];
  44. for (let i = 0; i < vectors.length; i += 2) {
  45. points.push([vectors[i], vectors[i + 1]]);
  46. }
  47. return points;
  48. });
  49. return [index, P];
  50. };
  51. /**
  52. * Convert value for each channel to line shapes.
  53. */
  54. export const Line = () => {
  55. return (index, scale, value, coordinate) => {
  56. const mark = isParallel(coordinate) ? parallel : line;
  57. return mark(index, scale, value, coordinate);
  58. };
  59. };
  60. const shapes = ['line', 'smooth'];
  61. Line.props = {
  62. defaultShape: 'line',
  63. defaultLabelShape: 'label',
  64. composite: false,
  65. channels: [
  66. ...baseGeometryChannels({ shapes }),
  67. { name: 'x' },
  68. { name: 'y' },
  69. { name: 'position', independent: true },
  70. { name: 'size' },
  71. { name: 'series', scale: 'identity' },
  72. ],
  73. preInference: [
  74. ...basePreInference(),
  75. { type: 'maybeSeries' },
  76. { type: 'maybeGradient' },
  77. ],
  78. postInference: [...basePostInference(), ...tooltip1d(), ...tooltipXd()],
  79. interaction: {
  80. shareTooltip: true,
  81. seriesTooltip: true,
  82. crosshairs: true,
  83. },
  84. };
  85. //# sourceMappingURL=line.js.map