funnelLayout.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. var layout = require("../../util/layout");
  2. var _number = require("../../util/number");
  3. var parsePercent = _number.parsePercent;
  4. var linearMap = _number.linearMap;
  5. function getViewRect(seriesModel, api) {
  6. return layout.getLayoutRect(seriesModel.getBoxLayoutParams(), {
  7. width: api.getWidth(),
  8. height: api.getHeight()
  9. });
  10. }
  11. function getSortedIndices(data, sort) {
  12. var valueArr = data.mapArray('value', function (val) {
  13. return val;
  14. });
  15. var indices = [];
  16. var isAscending = sort === 'ascending';
  17. for (var i = 0, len = data.count(); i < len; i++) {
  18. indices[i] = i;
  19. } // Add custom sortable function & none sortable opetion by "options.sort"
  20. if (typeof sort === 'function') {
  21. indices.sort(sort);
  22. } else if (sort !== 'none') {
  23. indices.sort(function (a, b) {
  24. return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a];
  25. });
  26. }
  27. return indices;
  28. }
  29. function labelLayout(data) {
  30. data.each(function (idx) {
  31. var itemModel = data.getItemModel(idx);
  32. var labelModel = itemModel.getModel('label.normal');
  33. var labelPosition = labelModel.get('position');
  34. var labelLineModel = itemModel.getModel('labelLine.normal');
  35. var layout = data.getItemLayout(idx);
  36. var points = layout.points;
  37. var isLabelInside = labelPosition === 'inner' || labelPosition === 'inside' || labelPosition === 'center';
  38. var textAlign;
  39. var textX;
  40. var textY;
  41. var linePoints;
  42. if (isLabelInside) {
  43. textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4;
  44. textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4;
  45. textAlign = 'center';
  46. linePoints = [[textX, textY], [textX, textY]];
  47. } else {
  48. var x1;
  49. var y1;
  50. var x2;
  51. var labelLineLen = labelLineModel.get('length');
  52. if (labelPosition === 'left') {
  53. // Left side
  54. x1 = (points[3][0] + points[0][0]) / 2;
  55. y1 = (points[3][1] + points[0][1]) / 2;
  56. x2 = x1 - labelLineLen;
  57. textX = x2 - 5;
  58. textAlign = 'right';
  59. } else {
  60. // Right side
  61. x1 = (points[1][0] + points[2][0]) / 2;
  62. y1 = (points[1][1] + points[2][1]) / 2;
  63. x2 = x1 + labelLineLen;
  64. textX = x2 + 5;
  65. textAlign = 'left';
  66. }
  67. var y2 = y1;
  68. linePoints = [[x1, y1], [x2, y2]];
  69. textY = y2;
  70. }
  71. layout.label = {
  72. linePoints: linePoints,
  73. x: textX,
  74. y: textY,
  75. verticalAlign: 'middle',
  76. textAlign: textAlign,
  77. inside: isLabelInside
  78. };
  79. });
  80. }
  81. function _default(ecModel, api, payload) {
  82. ecModel.eachSeriesByType('funnel', function (seriesModel) {
  83. var data = seriesModel.getData();
  84. var sort = seriesModel.get('sort');
  85. var viewRect = getViewRect(seriesModel, api);
  86. var indices = getSortedIndices(data, sort);
  87. var sizeExtent = [parsePercent(seriesModel.get('minSize'), viewRect.width), parsePercent(seriesModel.get('maxSize'), viewRect.width)];
  88. var dataExtent = data.getDataExtent('value');
  89. var min = seriesModel.get('min');
  90. var max = seriesModel.get('max');
  91. if (min == null) {
  92. min = Math.min(dataExtent[0], 0);
  93. }
  94. if (max == null) {
  95. max = dataExtent[1];
  96. }
  97. var funnelAlign = seriesModel.get('funnelAlign');
  98. var gap = seriesModel.get('gap');
  99. var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count();
  100. var y = viewRect.y;
  101. var getLinePoints = function (idx, offY) {
  102. // End point index is data.count() and we assign it 0
  103. var val = data.get('value', idx) || 0;
  104. var itemWidth = linearMap(val, [min, max], sizeExtent, true);
  105. var x0;
  106. switch (funnelAlign) {
  107. case 'left':
  108. x0 = viewRect.x;
  109. break;
  110. case 'center':
  111. x0 = viewRect.x + (viewRect.width - itemWidth) / 2;
  112. break;
  113. case 'right':
  114. x0 = viewRect.x + viewRect.width - itemWidth;
  115. break;
  116. }
  117. return [[x0, offY], [x0 + itemWidth, offY]];
  118. };
  119. if (sort === 'ascending') {
  120. // From bottom to top
  121. itemHeight = -itemHeight;
  122. gap = -gap;
  123. y += viewRect.height;
  124. indices = indices.reverse();
  125. }
  126. for (var i = 0; i < indices.length; i++) {
  127. var idx = indices[i];
  128. var nextIdx = indices[i + 1];
  129. var start = getLinePoints(idx, y);
  130. var end = getLinePoints(nextIdx, y + itemHeight);
  131. y += itemHeight + gap;
  132. data.setItemLayout(idx, {
  133. points: start.concat(end.slice().reverse())
  134. });
  135. }
  136. labelLayout(data);
  137. });
  138. }
  139. module.exports = _default;