pieLayout.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. import {parsePercent, linearMap} from '../../util/number';
  20. import * as layout from '../../util/layout';
  21. import labelLayout from './labelLayout';
  22. import * as zrUtil from 'zrender/src/core/util';
  23. var PI2 = Math.PI * 2;
  24. var RADIAN = Math.PI / 180;
  25. function getViewRect(seriesModel, api) {
  26. return layout.getLayoutRect(
  27. seriesModel.getBoxLayoutParams(), {
  28. width: api.getWidth(),
  29. height: api.getHeight()
  30. }
  31. );
  32. }
  33. export default function (seriesType, ecModel, api, payload) {
  34. ecModel.eachSeriesByType(seriesType, function (seriesModel) {
  35. var data = seriesModel.getData();
  36. var valueDim = data.mapDimension('value');
  37. var viewRect = getViewRect(seriesModel, api);
  38. var center = seriesModel.get('center');
  39. var radius = seriesModel.get('radius');
  40. if (!zrUtil.isArray(radius)) {
  41. radius = [0, radius];
  42. }
  43. if (!zrUtil.isArray(center)) {
  44. center = [center, center];
  45. }
  46. var width = parsePercent(viewRect.width, api.getWidth());
  47. var height = parsePercent(viewRect.height, api.getHeight());
  48. var size = Math.min(width, height);
  49. var cx = parsePercent(center[0], width) + viewRect.x;
  50. var cy = parsePercent(center[1], height) + viewRect.y;
  51. var r0 = parsePercent(radius[0], size / 2);
  52. var r = parsePercent(radius[1], size / 2);
  53. var startAngle = -seriesModel.get('startAngle') * RADIAN;
  54. var minAngle = seriesModel.get('minAngle') * RADIAN;
  55. var validDataCount = 0;
  56. data.each(valueDim, function (value) {
  57. !isNaN(value) && validDataCount++;
  58. });
  59. var sum = data.getSum(valueDim);
  60. // Sum may be 0
  61. var unitRadian = Math.PI / (sum || validDataCount) * 2;
  62. var clockwise = seriesModel.get('clockwise');
  63. var roseType = seriesModel.get('roseType');
  64. var stillShowZeroSum = seriesModel.get('stillShowZeroSum');
  65. // [0...max]
  66. var extent = data.getDataExtent(valueDim);
  67. extent[0] = 0;
  68. // In the case some sector angle is smaller than minAngle
  69. var restAngle = PI2;
  70. var valueSumLargerThanMinAngle = 0;
  71. var currentAngle = startAngle;
  72. var dir = clockwise ? 1 : -1;
  73. data.each(valueDim, function (value, idx) {
  74. var angle;
  75. if (isNaN(value)) {
  76. data.setItemLayout(idx, {
  77. angle: NaN,
  78. startAngle: NaN,
  79. endAngle: NaN,
  80. clockwise: clockwise,
  81. cx: cx,
  82. cy: cy,
  83. r0: r0,
  84. r: roseType
  85. ? NaN
  86. : r,
  87. viewRect: viewRect
  88. });
  89. return;
  90. }
  91. // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样?
  92. if (roseType !== 'area') {
  93. angle = (sum === 0 && stillShowZeroSum)
  94. ? unitRadian : (value * unitRadian);
  95. }
  96. else {
  97. angle = PI2 / validDataCount;
  98. }
  99. if (angle < minAngle) {
  100. angle = minAngle;
  101. restAngle -= minAngle;
  102. }
  103. else {
  104. valueSumLargerThanMinAngle += value;
  105. }
  106. var endAngle = currentAngle + dir * angle;
  107. data.setItemLayout(idx, {
  108. angle: angle,
  109. startAngle: currentAngle,
  110. endAngle: endAngle,
  111. clockwise: clockwise,
  112. cx: cx,
  113. cy: cy,
  114. r0: r0,
  115. r: roseType
  116. ? linearMap(value, extent, [r0, r])
  117. : r,
  118. viewRect: viewRect
  119. });
  120. currentAngle = endAngle;
  121. });
  122. // Some sector is constrained by minAngle
  123. // Rest sectors needs recalculate angle
  124. if (restAngle < PI2 && validDataCount) {
  125. // Average the angle if rest angle is not enough after all angles is
  126. // Constrained by minAngle
  127. if (restAngle <= 1e-3) {
  128. var angle = PI2 / validDataCount;
  129. data.each(valueDim, function (value, idx) {
  130. if (!isNaN(value)) {
  131. var layout = data.getItemLayout(idx);
  132. layout.angle = angle;
  133. layout.startAngle = startAngle + dir * idx * angle;
  134. layout.endAngle = startAngle + dir * (idx + 1) * angle;
  135. }
  136. });
  137. }
  138. else {
  139. unitRadian = restAngle / valueSumLargerThanMinAngle;
  140. currentAngle = startAngle;
  141. data.each(valueDim, function (value, idx) {
  142. if (!isNaN(value)) {
  143. var layout = data.getItemLayout(idx);
  144. var angle = layout.angle === minAngle
  145. ? minAngle : value * unitRadian;
  146. layout.startAngle = currentAngle;
  147. layout.endAngle = currentAngle + dir * angle;
  148. currentAngle += dir * angle;
  149. }
  150. });
  151. }
  152. }
  153. labelLayout(seriesModel, r, viewRect.width, viewRect.height, viewRect.x, viewRect.y);
  154. });
  155. }