163 lines
7.0 KiB
JavaScript
163 lines
7.0 KiB
JavaScript
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
|
|
/**
|
|
* AUTO-GENERATED FILE. DO NOT MODIFY.
|
|
*/
|
|
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
import { assert, each } from 'zrender/lib/core/util.js';
|
|
import { isOrdinalScale } from '../scale/helper.js';
|
|
import { isNullableNumberFinite, mathAbs, mathMax } from '../util/number.js';
|
|
import { getAxisStat, getAxisStatBySeries, LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE } from './axisStatistics.js';
|
|
import { getScaleLinearSpanForMapping } from '../scale/scaleMapper.js';
|
|
// Arbitrary, leave some space to avoid overflowing when dataZoom moving.
|
|
var FALLBACK_BAND_WIDTH_RATIO = 0.8;
|
|
/**
|
|
* NOTICE:
|
|
* - Require the axis pixel extent and the scale extent as inputs. But they
|
|
* can be not precise for approximation.
|
|
* - Can only be called after "data processing" stage.
|
|
*
|
|
* PENDING:
|
|
* Currently `bandWidth` can not be specified by users explicitly. But if we
|
|
* allow that in future, these issues must be considered:
|
|
* - Can only allow specifying a band width in data scale rather than pixel.
|
|
* - LogScale needs to be considered - band width can only be specified on linear
|
|
* (but before break) scale, similar to `axis.interval`.
|
|
*
|
|
* A band is required on:
|
|
* - series group band width in bar/boxplot/candlestick/...;
|
|
* - tooltip axisPointer type "shadow";
|
|
* - etc.
|
|
*/
|
|
export function calcBandWidth(axis, opt) {
|
|
opt = opt || {};
|
|
var out = {
|
|
w: NaN,
|
|
w2: NaN
|
|
};
|
|
var scale = axis.scale;
|
|
var fromStat = opt.fromStat;
|
|
var min = opt.min;
|
|
// [BAND_WIDTH_USED_SCALE_LINEAR_SPAN]
|
|
// - Band width should always respect to the currently specified extent, and `SCALE_EXTENT_KIND_MAPPING`
|
|
// should be used if specified.
|
|
// Otherwise, the result may incorrect, especially when data count is small.
|
|
// For example, when "containShape" is calculating, no `SCALE_EXTENT_KIND_MAPPING` is set, so here only
|
|
// `SCALE_EXTENT_KIND_EFFECTIVE` is returned, say, `[3, 5]`, based on which a `SCALE_EXTENT_KIND_MAPPING`
|
|
// is calculated, say `[2.5, 5.5]` (expanded by `0.5`). Then when rendering, that `SCALE_EXTENT_KIND_MAPPING`
|
|
// is returned here.
|
|
// See AXIS_CONTAIN_SHAPE_COMMON_STRATEGY for more details.
|
|
// - The span should be in the linear space (typically, the innermost space).
|
|
// - We use the scale extent after being zoommed and `intervalScaleEnsureValidExtent`-ish applied and
|
|
// "nice"/"align" applied, because:
|
|
// - For OrdinalScale, fine;
|
|
// - For numeric scale, `scaleLinearSpan` is normally not used for a consistent result when `dataZoom`
|
|
// is applied, but used when none or single data item case.
|
|
var scaleLinearSpan = getScaleLinearSpanForMapping(scale);
|
|
if (!isNullableNumberFinite(scaleLinearSpan)) {
|
|
// scale may be `[Infinity, -Infinity]`.
|
|
scaleLinearSpan = NaN;
|
|
}
|
|
var axisExtent = axis.getExtent();
|
|
// Always use a new pxSpan because it may be changed in `grid` contain label calculation.
|
|
var pxSpan = mathAbs(axisExtent[1] - axisExtent[0]);
|
|
if (isOrdinalScale(scale)) {
|
|
calcBandWidthForCategoryAxis(out, axis, scaleLinearSpan, pxSpan);
|
|
} else if (fromStat) {
|
|
calcBandWidthForNumericAxis(out, axis, scaleLinearSpan, pxSpan, fromStat);
|
|
} else if (min == null) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(false);
|
|
}
|
|
}
|
|
if (min != null) {
|
|
out.w = isNullableNumberFinite(out.w) ? mathMax(min, out.w) : min;
|
|
}
|
|
return out;
|
|
}
|
|
function calcBandWidthForCategoryAxis(out, axis, scaleLinearSpan, pxSpan) {
|
|
var onBand = axis.onBand;
|
|
var len = scaleLinearSpan + (onBand ? 1 : 0);
|
|
// Fix #2728, avoid NaN when only one data.
|
|
len === 0 && (len = 1);
|
|
out.w = pxSpan / len;
|
|
// NOTE:
|
|
// - When `scaleLinearSpan === 0`, no need to expand extent.
|
|
// - `onBand: true` (`boundaryGap: true`) does not need to support `containShape`,
|
|
// thereby no `invRatio`.
|
|
if (!onBand && scaleLinearSpan && pxSpan) {
|
|
out.w2 = out.w * scaleLinearSpan / pxSpan;
|
|
}
|
|
}
|
|
function calcBandWidthForNumericAxis(out, axis, scaleLinearSpan, pxSpan, fromStat) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(fromStat);
|
|
}
|
|
var onlySingular = false;
|
|
var bandWidthInData = -Infinity;
|
|
each(fromStat.key ? [getAxisStat(axis, fromStat.key)] : getAxisStatBySeries(axis, fromStat.sers || []), function (stat) {
|
|
var liPosMinGap = stat.liPosMinGap;
|
|
// NOTE: `liPosMinGap == null` may indicate that `requireAxisStatistics`
|
|
// is not used by any series on this axis. We should not make `bandWidth`
|
|
// for this case.
|
|
if (liPosMinGap != null) {
|
|
if (liPosMinGap > 0) {
|
|
if (liPosMinGap > bandWidthInData) {
|
|
bandWidthInData = liPosMinGap;
|
|
}
|
|
onlySingular = false;
|
|
} else if (liPosMinGap === LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE) {
|
|
onlySingular = true;
|
|
}
|
|
}
|
|
});
|
|
if (isNullableNumberFinite(scaleLinearSpan) && scaleLinearSpan > 0 && isNullableNumberFinite(bandWidthInData)) {
|
|
out.w = pxSpan / scaleLinearSpan * bandWidthInData;
|
|
out.w2 = bandWidthInData;
|
|
} else if (onlySingular) {
|
|
// This is the special handing for single value case, where min gap can not
|
|
// be calculated, but `w` and `w2` (for "containShape") are still needed.
|
|
out.w = pxSpan * FALLBACK_BAND_WIDTH_RATIO;
|
|
out.w2 = out.w * scaleLinearSpan / pxSpan;
|
|
// Consider an axis has both candlestick and bar series, where candlestick has multiple data
|
|
// but the bar series has no data. In this case, that bar series should be ignored; otherwise,
|
|
// the axis will be significantly expanded by "containShape" but no bar shape displayed.
|
|
}
|
|
} |