DistributeElementsHandler.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import {
  2. forEach,
  3. sortBy
  4. } from 'min-dash';
  5. /**
  6. * A handler that distributes elements evenly.
  7. */
  8. export default function DistributeElements(modeling) {
  9. this._modeling = modeling;
  10. }
  11. DistributeElements.$inject = [ 'modeling' ];
  12. var OFF_AXIS = {
  13. x: 'y',
  14. y: 'x'
  15. };
  16. DistributeElements.prototype.preExecute = function(context) {
  17. var modeling = this._modeling;
  18. var groups = context.groups,
  19. axis = context.axis,
  20. dimension = context.dimension;
  21. function updateRange(group, element) {
  22. group.range.min = Math.min(element[axis], group.range.min);
  23. group.range.max = Math.max(element[axis] + element[dimension], group.range.max);
  24. }
  25. function center(element) {
  26. return element[axis] + element[dimension] / 2;
  27. }
  28. function lastIdx(arr) {
  29. return arr.length - 1;
  30. }
  31. function rangeDiff(range) {
  32. return range.max - range.min;
  33. }
  34. function centerElement(refCenter, element) {
  35. var delta = { y: 0 };
  36. delta[axis] = refCenter - center(element);
  37. if (delta[axis]) {
  38. delta[OFF_AXIS[axis]] = 0;
  39. modeling.moveElements([ element ], delta, element.parent);
  40. }
  41. }
  42. var firstGroup = groups[0],
  43. lastGroupIdx = lastIdx(groups),
  44. lastGroup = groups[ lastGroupIdx ];
  45. var margin,
  46. spaceInBetween,
  47. groupsSize = 0; // the size of each range
  48. forEach(groups, function(group, idx) {
  49. var sortedElements,
  50. refElem,
  51. refCenter;
  52. if (group.elements.length < 2) {
  53. if (idx && idx !== groups.length - 1) {
  54. updateRange(group, group.elements[0]);
  55. groupsSize += rangeDiff(group.range);
  56. }
  57. return;
  58. }
  59. sortedElements = sortBy(group.elements, axis);
  60. refElem = sortedElements[0];
  61. if (idx === lastGroupIdx) {
  62. refElem = sortedElements[lastIdx(sortedElements)];
  63. }
  64. refCenter = center(refElem);
  65. // wanna update the ranges after the shapes have been centered
  66. group.range = null;
  67. forEach(sortedElements, function(element) {
  68. centerElement(refCenter, element);
  69. if (group.range === null) {
  70. group.range = {
  71. min: element[axis],
  72. max: element[axis] + element[dimension]
  73. };
  74. return;
  75. }
  76. // update group's range after centering the range elements
  77. updateRange(group, element);
  78. });
  79. if (idx && idx !== groups.length - 1) {
  80. groupsSize += rangeDiff(group.range);
  81. }
  82. });
  83. spaceInBetween = Math.abs(lastGroup.range.min - firstGroup.range.max);
  84. margin = Math.round((spaceInBetween - groupsSize) / (groups.length - 1));
  85. if (margin < groups.length - 1) {
  86. return;
  87. }
  88. forEach(groups, function(group, groupIdx) {
  89. var delta = {},
  90. prevGroup;
  91. if (group === firstGroup || group === lastGroup) {
  92. return;
  93. }
  94. prevGroup = groups[groupIdx - 1];
  95. group.range.max = 0;
  96. forEach(group.elements, function(element, idx) {
  97. delta[OFF_AXIS[axis]] = 0;
  98. delta[axis] = (prevGroup.range.max - element[axis]) + margin;
  99. if (group.range.min !== element[axis]) {
  100. delta[axis] += element[axis] - group.range.min;
  101. }
  102. if (delta[axis]) {
  103. modeling.moveElements([ element ], delta, element.parent);
  104. }
  105. group.range.max = Math.max(element[axis] + element[dimension], idx ? group.range.max : 0);
  106. });
  107. });
  108. };
  109. DistributeElements.prototype.postExecute = function(context) {
  110. };