axisBand.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import { assert, each } from 'zrender/lib/core/util.js';
  41. import { isOrdinalScale } from '../scale/helper.js';
  42. import { isNullableNumberFinite, mathAbs, mathMax } from '../util/number.js';
  43. import { getAxisStat, getAxisStatBySeries, LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE } from './axisStatistics.js';
  44. import { getScaleLinearSpanForMapping } from '../scale/scaleMapper.js';
  45. // Arbitrary, leave some space to avoid overflowing when dataZoom moving.
  46. var FALLBACK_BAND_WIDTH_RATIO = 0.8;
  47. /**
  48. * NOTICE:
  49. * - Require the axis pixel extent and the scale extent as inputs. But they
  50. * can be not precise for approximation.
  51. * - Can only be called after "data processing" stage.
  52. *
  53. * PENDING:
  54. * Currently `bandWidth` can not be specified by users explicitly. But if we
  55. * allow that in future, these issues must be considered:
  56. * - Can only allow specifying a band width in data scale rather than pixel.
  57. * - LogScale needs to be considered - band width can only be specified on linear
  58. * (but before break) scale, similar to `axis.interval`.
  59. *
  60. * A band is required on:
  61. * - series group band width in bar/boxplot/candlestick/...;
  62. * - tooltip axisPointer type "shadow";
  63. * - etc.
  64. */
  65. export function calcBandWidth(axis, opt) {
  66. opt = opt || {};
  67. var out = {
  68. w: NaN,
  69. w2: NaN
  70. };
  71. var scale = axis.scale;
  72. var fromStat = opt.fromStat;
  73. var min = opt.min;
  74. // [BAND_WIDTH_USED_SCALE_LINEAR_SPAN]
  75. // - Band width should always respect to the currently specified extent, and `SCALE_EXTENT_KIND_MAPPING`
  76. // should be used if specified.
  77. // Otherwise, the result may incorrect, especially when data count is small.
  78. // For example, when "containShape" is calculating, no `SCALE_EXTENT_KIND_MAPPING` is set, so here only
  79. // `SCALE_EXTENT_KIND_EFFECTIVE` is returned, say, `[3, 5]`, based on which a `SCALE_EXTENT_KIND_MAPPING`
  80. // is calculated, say `[2.5, 5.5]` (expanded by `0.5`). Then when rendering, that `SCALE_EXTENT_KIND_MAPPING`
  81. // is returned here.
  82. // See AXIS_CONTAIN_SHAPE_COMMON_STRATEGY for more details.
  83. // - The span should be in the linear space (typically, the innermost space).
  84. // - We use the scale extent after being zoommed and `intervalScaleEnsureValidExtent`-ish applied and
  85. // "nice"/"align" applied, because:
  86. // - For OrdinalScale, fine;
  87. // - For numeric scale, `scaleLinearSpan` is normally not used for a consistent result when `dataZoom`
  88. // is applied, but used when none or single data item case.
  89. var scaleLinearSpan = getScaleLinearSpanForMapping(scale);
  90. if (!isNullableNumberFinite(scaleLinearSpan)) {
  91. // scale may be `[Infinity, -Infinity]`.
  92. scaleLinearSpan = NaN;
  93. }
  94. var axisExtent = axis.getExtent();
  95. // Always use a new pxSpan because it may be changed in `grid` contain label calculation.
  96. var pxSpan = mathAbs(axisExtent[1] - axisExtent[0]);
  97. if (isOrdinalScale(scale)) {
  98. calcBandWidthForCategoryAxis(out, axis, scaleLinearSpan, pxSpan);
  99. } else if (fromStat) {
  100. calcBandWidthForNumericAxis(out, axis, scaleLinearSpan, pxSpan, fromStat);
  101. } else if (min == null) {
  102. if (process.env.NODE_ENV !== 'production') {
  103. assert(false);
  104. }
  105. }
  106. if (min != null) {
  107. out.w = isNullableNumberFinite(out.w) ? mathMax(min, out.w) : min;
  108. }
  109. return out;
  110. }
  111. function calcBandWidthForCategoryAxis(out, axis, scaleLinearSpan, pxSpan) {
  112. var onBand = axis.onBand;
  113. var len = scaleLinearSpan + (onBand ? 1 : 0);
  114. // Fix #2728, avoid NaN when only one data.
  115. len === 0 && (len = 1);
  116. out.w = pxSpan / len;
  117. // NOTE:
  118. // - When `scaleLinearSpan === 0`, no need to expand extent.
  119. // - `onBand: true` (`boundaryGap: true`) does not need to support `containShape`,
  120. // thereby no `invRatio`.
  121. if (!onBand && scaleLinearSpan && pxSpan) {
  122. out.w2 = out.w * scaleLinearSpan / pxSpan;
  123. }
  124. }
  125. function calcBandWidthForNumericAxis(out, axis, scaleLinearSpan, pxSpan, fromStat) {
  126. if (process.env.NODE_ENV !== 'production') {
  127. assert(fromStat);
  128. }
  129. var onlySingular = false;
  130. var bandWidthInData = -Infinity;
  131. each(fromStat.key ? [getAxisStat(axis, fromStat.key)] : getAxisStatBySeries(axis, fromStat.sers || []), function (stat) {
  132. var liPosMinGap = stat.liPosMinGap;
  133. // NOTE: `liPosMinGap == null` may indicate that `requireAxisStatistics`
  134. // is not used by any series on this axis. We should not make `bandWidth`
  135. // for this case.
  136. if (liPosMinGap != null) {
  137. if (liPosMinGap > 0) {
  138. if (liPosMinGap > bandWidthInData) {
  139. bandWidthInData = liPosMinGap;
  140. }
  141. onlySingular = false;
  142. } else if (liPosMinGap === LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE) {
  143. onlySingular = true;
  144. }
  145. }
  146. });
  147. if (isNullableNumberFinite(scaleLinearSpan) && scaleLinearSpan > 0 && isNullableNumberFinite(bandWidthInData)) {
  148. out.w = pxSpan / scaleLinearSpan * bandWidthInData;
  149. out.w2 = bandWidthInData;
  150. } else if (onlySingular) {
  151. // This is the special handing for single value case, where min gap can not
  152. // be calculated, but `w` and `w2` (for "containShape") are still needed.
  153. out.w = pxSpan * FALLBACK_BAND_WIDTH_RATIO;
  154. out.w2 = out.w * scaleLinearSpan / pxSpan;
  155. // Consider an axis has both candlestick and bar series, where candlestick has multiple data
  156. // but the bar series has no data. In this case, that bar series should be ignored; otherwise,
  157. // the axis will be significantly expanded by "containShape" but no bar shape displayed.
  158. }
  159. }