stackEnter.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { deepMix } from '@antv/util';
  2. import { group, max } from 'd3-array';
  3. import { columnOf, constant, maybeColumnOf, visualColumn, } from './utils/helper';
  4. /**
  5. * Group marks by channels into groups and stacking their enterDelay
  6. * to make marks show up groups by groups.
  7. * It will update enterDelay channel for each mark by its enterDuration and group.
  8. * @todo Support orderBy.
  9. * @todo Sort among groups(e.g. reverse).
  10. * @todo Stack enter in groups rather than between groups?
  11. * @todo Auto inter this statistic for scaleInY animation in stacked interval?
  12. * @todo All the groups shared the enterDuration?
  13. */
  14. export const StackEnter = (options) => {
  15. const { groupBy = ['x'], reducer = (I, V) => V[I[0]], orderBy = null, reverse = false, duration, } = options;
  16. return (I, mark) => {
  17. const { encode } = mark;
  18. // Extract group information by each specified channel,
  19. // and skip if all values of channels are empty.
  20. const by = Array.isArray(groupBy) ? groupBy : [groupBy];
  21. const groupEntries = by.map((k) => [k, columnOf(encode, k)[0]]);
  22. if (groupEntries.length === 0)
  23. return [I, mark];
  24. // Nest group index and flatten them in right order among timeline.
  25. // [[1, 2, 3, 4, 5, 6]] ->
  26. // [[1, 2, 3], [4, 5, 6]] ->
  27. // [[1], [2], [3], [4], [5], [6]]
  28. let groups = [I];
  29. for (const [, V] of groupEntries) {
  30. const newGroups = [];
  31. for (const I of groups) {
  32. const G = Array.from(group(I, (i) => V[i]).values());
  33. // @todo sort by x.
  34. newGroups.push(...G);
  35. }
  36. groups = newGroups;
  37. }
  38. // const {color} = encode;
  39. if (orderBy) {
  40. const [V] = columnOf(encode, orderBy);
  41. if (V)
  42. groups.sort((I, J) => reducer(I, V) - reducer(J, V));
  43. if (reverse)
  44. groups.reverse();
  45. }
  46. // Stack delay for each group.
  47. const t = (duration || 3000) / groups.length;
  48. const [ED] = duration
  49. ? [constant(I, t)] // If specified duration, generate enter duration for each.
  50. : maybeColumnOf(encode, 'enterDuration', constant(I, t));
  51. const [EDL] = maybeColumnOf(encode, 'enterDelay', constant(I, 0));
  52. const newEnterDelay = new Array(I.length);
  53. for (let i = 0, pd = 0; i < groups.length; i++) {
  54. const I = groups[i];
  55. const maxDuration = max(I, (i) => +ED[i]);
  56. for (const j of I)
  57. newEnterDelay[j] = +EDL[j] + pd;
  58. pd += maxDuration;
  59. }
  60. return [
  61. I,
  62. deepMix({}, mark, {
  63. encode: {
  64. enterDuration: visualColumn(ED),
  65. enterDelay: visualColumn(newEnterDelay),
  66. },
  67. }),
  68. ];
  69. };
  70. };
  71. StackEnter.props = {};
  72. //# sourceMappingURL=stackEnter.js.map