echarts
Version:
Apache ECharts is a powerful, interactive charting and data visualization library for browser
163 lines (159 loc) • 7.14 kB
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.
}
}