前端初始化
This commit is contained in:
+319
@@ -0,0 +1,319 @@
|
||||
|
||||
/*
|
||||
* 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 { getAcceptableTickPrecision, isNullableNumberFinite, mathAbs, mathCeil, mathFloor, mathMax, mathRound, nice, NICE_MODE_MIN, quantity, round } from '../util/number.js';
|
||||
import IntervalScale from '../scale/Interval.js';
|
||||
import LogScale from '../scale/Log.js';
|
||||
import { updateIntervalOrLogScaleForNiceOrAligned } from './axisHelper.js';
|
||||
import { warn } from '../util/log.js';
|
||||
import { increaseInterval, isLogScale, getIntervalPrecision, intervalScaleEnsureValidExtent } from '../scale/helper.js';
|
||||
import { assert } from 'zrender/lib/core/util.js';
|
||||
import { adoptScaleRawExtentInfoAndPrepare } from './scaleRawExtentInfo.js';
|
||||
import { hasBreaks } from '../scale/break.js';
|
||||
/**
|
||||
* NOTE: See the summary of the process of extent determination in the comment of `scaleMapper.setExtent`.
|
||||
*
|
||||
* @see SCALE_EXTENT_CONSTRUCTION for the full processing flow.
|
||||
*/
|
||||
export function scaleCalcAlign(targetAxis, alignToScale) {
|
||||
var targetScale = targetAxis.scale;
|
||||
var targetAxisModel = targetAxis.model;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
assert(targetScale && targetAxisModel && (targetScale instanceof IntervalScale || targetScale instanceof LogScale) && (alignToScale instanceof IntervalScale || alignToScale instanceof LogScale));
|
||||
}
|
||||
var targetExtentInfo = adoptScaleRawExtentInfoAndPrepare(targetScale, targetAxisModel, targetAxisModel.ecModel, targetAxis, null);
|
||||
// FIXME:
|
||||
// (1) Axis inverse is not considered yet.
|
||||
// (2) `SCALE_EXTENT_KIND_MAPPING` is not considered yet.
|
||||
var isTargetLogScale = isLogScale(targetScale);
|
||||
var alignToScaleLinear = isLogScale(alignToScale) ? alignToScale.intervalStub : alignToScale;
|
||||
var targetIntervalStub = isTargetLogScale ? targetScale.intervalStub : targetScale;
|
||||
var targetLogScaleBase = targetScale.base;
|
||||
var alignToTicks = alignToScaleLinear.getTicks();
|
||||
var alignToExpNiceTicks = alignToScaleLinear.getTicks({
|
||||
expandToNicedExtent: true
|
||||
});
|
||||
var alignToSegCount = alignToTicks.length - 1;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// This is guards for future changes of `Interval#getTicks`.
|
||||
assert(!hasBreaks(alignToScale) && !hasBreaks(targetScale));
|
||||
assert(alignToSegCount > 0); // Ticks length >= 2 even on a blank scale.
|
||||
assert(alignToExpNiceTicks.length === alignToTicks.length);
|
||||
assert(alignToTicks[0].value <= alignToTicks[alignToSegCount].value);
|
||||
assert(alignToExpNiceTicks[0].value <= alignToTicks[0].value && alignToTicks[alignToSegCount].value <= alignToExpNiceTicks[alignToSegCount].value);
|
||||
if (alignToSegCount >= 2) {
|
||||
assert(alignToExpNiceTicks[1].value === alignToTicks[1].value);
|
||||
assert(alignToExpNiceTicks[alignToSegCount - 1].value === alignToTicks[alignToSegCount - 1].value);
|
||||
}
|
||||
}
|
||||
// The Current strategy: Find a proper interval and an extent for the target scale to derive ticks
|
||||
// matching exactly to ticks of `alignTo` scale.
|
||||
// Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale
|
||||
var t0; // diff ratio on min not-nice segment. 0 <= t0 < 1
|
||||
var t1; // diff ratio on max not-nice segment. 0 <= t1 < 1
|
||||
var alignToNiceSegCount; // >= 1
|
||||
// Consider ticks of `alignTo`, only these cases below may occur:
|
||||
if (alignToSegCount === 1) {
|
||||
// `alignToTicks` is like:
|
||||
// |--|
|
||||
// In this case, we make the corresponding 2 target ticks "nice".
|
||||
t0 = t1 = 0;
|
||||
alignToNiceSegCount = 1;
|
||||
} else if (alignToSegCount === 2) {
|
||||
// `alignToTicks` is like:
|
||||
// |-|-----| or
|
||||
// |-----|-| or
|
||||
// |-----|-----|
|
||||
// Notices that nice ticks do not necessarily exist in this case.
|
||||
// In this case, we choose the larger segment as the "nice segment" and
|
||||
// the corresponding target ticks are made "nice".
|
||||
var interval0 = mathAbs(alignToTicks[0].value - alignToTicks[1].value);
|
||||
var interval1 = mathAbs(alignToTicks[1].value - alignToTicks[2].value);
|
||||
t0 = t1 = 0;
|
||||
if (interval0 === interval1) {
|
||||
alignToNiceSegCount = 2;
|
||||
} else {
|
||||
alignToNiceSegCount = 1;
|
||||
if (interval0 < interval1) {
|
||||
t0 = interval0 / interval1;
|
||||
} else {
|
||||
t1 = interval1 / interval0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// alignToSegCount >= 3
|
||||
// `alignToTicks` is like:
|
||||
// |-|-----|-----|-| or
|
||||
// |-----|-----|-| or
|
||||
// |-|-----|-----| or ...
|
||||
// At least one nice segment is present, and not-nice segments are only present on
|
||||
// the start and/or the end.
|
||||
// In this case, ticks corresponding to nice segments are made "nice".
|
||||
var alignToInterval = alignToScaleLinear.getConfig().interval;
|
||||
t0 = (1 - (alignToTicks[0].value - alignToExpNiceTicks[0].value) / alignToInterval) % 1;
|
||||
t1 = (1 - (alignToExpNiceTicks[alignToSegCount].value - alignToTicks[alignToSegCount].value) / alignToInterval) % 1;
|
||||
alignToNiceSegCount = alignToSegCount - (t0 ? 1 : 0) - (t1 ? 1 : 0);
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
assert(alignToNiceSegCount >= 1);
|
||||
}
|
||||
// NOTE:
|
||||
// Consider a case:
|
||||
// dataZoom controls all Y axes;
|
||||
// dataZoom end is 90% (maxFixed: true, dataZoomFixMinMax[0]: true);
|
||||
// but dataZoom start is 0% (minFixed: false, dataZoomFixMinMax[1]: false);
|
||||
// In this case,
|
||||
// - `Interval#calcNiceTicks` only uses `targetExtentInfo.max` as the upper bound, but expand the
|
||||
// lower bound to a "nice" tick and can get an acceptable result.
|
||||
// - `scaleCalcAlign` has to use both `targetExtentInfo.min/max` as the bounds without any expansion,
|
||||
// otherwise the lower bound may become negative unexpectedly, especially for all positive series data.
|
||||
var dataZoomFixMinMax = targetExtentInfo.zoomFixMM;
|
||||
var hasDataZoomFixMinMax = dataZoomFixMinMax[0] || dataZoomFixMinMax[1];
|
||||
var targetMinMaxFixed = [targetExtentInfo.fixMM[0] || hasDataZoomFixMinMax, targetExtentInfo.fixMM[1] || hasDataZoomFixMinMax];
|
||||
// MEMO: When only `xxxAxis.min` or `xxxAxis.max` is fixed,
|
||||
// - Even a "nice" interval can be calculated, ticks accumulated based on `min`/`max` can be "nice" only if
|
||||
// `min` or `max` is a "nice" number.
|
||||
// - Generating a "nice" interval may cause the extent have both positive and negative ticks, which may be
|
||||
// not preferable for all positive (very common) or all negative series data. But it can be simply resolved
|
||||
// by specifying `xxxAxis.min: 0`/`xxxAxis.max: 0`, so we do not specially handle this case here.
|
||||
// Therefore, we prioritize generating "nice" interval over preventing from crossing zero.
|
||||
// e.g., if series data are all positive and the max data is `11739`,
|
||||
// If setting `yAxis.max: 'dataMax'`, ticks may be like:
|
||||
// `11739, 8739, 5739, 2739, -1739` (not "nice" enough)
|
||||
// If setting `yAxis.max: 'dataMax', yAxis.min: 0`, ticks may be like:
|
||||
// `11739, 8805, 5870, 2935, 0` (not "nice" enough but may be acceptable)
|
||||
// If setting `yAxis.max: 12000, yAxis.min: 0`, ticks may be like:
|
||||
// `12000, 9000, 6000, 3000, 0` ("nice")
|
||||
var targetOldOutermostExtent = targetScale.getExtent();
|
||||
var targetOldIntervalExtent = targetIntervalStub.getExtent();
|
||||
var targetExtent = intervalScaleEnsureValidExtent(targetOldIntervalExtent, targetMinMaxFixed);
|
||||
var min;
|
||||
var max;
|
||||
var interval;
|
||||
var intervalPrecision;
|
||||
var maxNice;
|
||||
var minNice;
|
||||
function loopIncreaseInterval(cb) {
|
||||
// Typically this loop runs less than 5 times. But we still
|
||||
// use a fail-safe for future changes.
|
||||
var LOOP_MAX = 50;
|
||||
var loopGuard = 0;
|
||||
for (; loopGuard < LOOP_MAX; loopGuard++) {
|
||||
if (cb()) {
|
||||
break;
|
||||
}
|
||||
interval = isTargetLogScale
|
||||
// TODO: `mathMax(base, 2)` is a guardcode to avoid infinite loop,
|
||||
// but probably it should be guranteed by `LogScale` itself.
|
||||
? interval * mathMax(targetLogScaleBase, 2) : increaseInterval(interval);
|
||||
intervalPrecision = getIntervalPrecision(interval);
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (loopGuard >= LOOP_MAX) {
|
||||
warn('incorrect impl in `scaleCalcAlign`.');
|
||||
}
|
||||
}
|
||||
}
|
||||
function updateMinFromMinNice() {
|
||||
min = round(minNice - interval * t0, intervalPrecision);
|
||||
}
|
||||
function updateMaxFromMaxNice() {
|
||||
max = round(maxNice + interval * t1, intervalPrecision);
|
||||
}
|
||||
function updateMinNiceFromMinT0Interval() {
|
||||
minNice = t0 ? round(min + interval * t0, intervalPrecision) : min;
|
||||
}
|
||||
function updateMaxNiceFromMaxT1Interval() {
|
||||
maxNice = t1 ? round(max - interval * t1, intervalPrecision) : max;
|
||||
}
|
||||
// NOTE: The new calculated `min`/`max` must NOT shrink the original extent; otherwise some series
|
||||
// data may be outside of the extent. They can expand the original extent slightly to align with
|
||||
// ticks of `alignTo`. In this case, more blank space is added but visually fine.
|
||||
if (targetMinMaxFixed[0] && targetMinMaxFixed[1]) {
|
||||
// Both `min` and `max` are specified (via dataZoom or ec option; consider both Cartesian, radar and
|
||||
// other possible axes). In this case, "nice" ticks can hardly be calculated, but reasonable ticks should
|
||||
// still be calculated whenever possible, especially `intervalPrecision` should be tuned for better
|
||||
// appearance and lower cumulative error.
|
||||
min = targetExtent[0];
|
||||
max = targetExtent[1];
|
||||
interval = (max - min) / (alignToNiceSegCount + t0 + t1);
|
||||
// Typically axis pixel extent is ready here. See `create` in `Grid.ts`.
|
||||
var axisPxExtent = targetAxis.getExtent();
|
||||
// NOTICE: this pxSpan may be not accurate yet due to "outerBounds" logic, but acceptable so far.
|
||||
var pxSpan = mathAbs(axisPxExtent[1] - axisPxExtent[0]);
|
||||
// We imperically choose `pxDiffAcceptable` as `0.5 / alignToNiceSegCount` for reduce cumulative
|
||||
// error, otherwise a discernible misalign (> 1px) may occur.
|
||||
// PENDING: We do not find a acceptable precision for LogScale here.
|
||||
// Theoretically it can be addressed but introduce more complexity. Is it necessary?
|
||||
intervalPrecision = getAcceptableTickPrecision([max, min], pxSpan, 0.5 / alignToNiceSegCount);
|
||||
updateMinNiceFromMinT0Interval();
|
||||
updateMaxNiceFromMaxT1Interval();
|
||||
if (isNullableNumberFinite(intervalPrecision)) {
|
||||
interval = round(interval, intervalPrecision);
|
||||
}
|
||||
} else {
|
||||
// Make a minimal enough `interval`, increase it later.
|
||||
// It is a similar logic as `IntervalScale#calcNiceTicks` and `LogScale#calcNiceTicks`.
|
||||
// Axis break is not supported, which is guranteed by the caller of this function.
|
||||
var targetSpan = targetExtent[1] - targetExtent[0];
|
||||
interval = isTargetLogScale ? mathMax(quantity(targetSpan), 1) : nice(targetSpan / alignToNiceSegCount, NICE_MODE_MIN);
|
||||
intervalPrecision = getIntervalPrecision(interval);
|
||||
if (targetMinMaxFixed[0]) {
|
||||
min = targetExtent[0];
|
||||
loopIncreaseInterval(function () {
|
||||
updateMinNiceFromMinT0Interval();
|
||||
maxNice = round(minNice + interval * alignToNiceSegCount, intervalPrecision);
|
||||
updateMaxFromMaxNice();
|
||||
if (max >= targetExtent[1]) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else if (targetMinMaxFixed[1]) {
|
||||
max = targetExtent[1];
|
||||
loopIncreaseInterval(function () {
|
||||
updateMaxNiceFromMaxT1Interval();
|
||||
minNice = round(maxNice - interval * alignToNiceSegCount, intervalPrecision);
|
||||
updateMinFromMinNice();
|
||||
if (min <= targetExtent[0]) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
loopIncreaseInterval(function () {
|
||||
minNice = round(mathCeil(targetExtent[0] / interval) * interval, intervalPrecision);
|
||||
maxNice = round(mathFloor(targetExtent[1] / interval) * interval, intervalPrecision);
|
||||
// NOTE:
|
||||
// - `maxNice - minNice >= -interval` here.
|
||||
// - While `interval` increases, `currIntervalCount` decreases, minimum `-1`.
|
||||
var currIntervalCount = mathRound((maxNice - minNice) / interval);
|
||||
if (currIntervalCount <= alignToNiceSegCount) {
|
||||
var moreCount = alignToNiceSegCount - currIntervalCount;
|
||||
// Consider cases that negative tick do not make sense (or vice versa), users can simply
|
||||
// specify `xxxAxis.min/max: 0` to avoid negative. But we still automatically handle it
|
||||
// for some common cases whenever possible:
|
||||
// - When ec option is `xxxAxis.scale: false` (the default), it is usually unexpected if
|
||||
// negative (or positive) ticks are introduced.
|
||||
// - In LogScale, series data are usually either all > 1 or all < 1, rather than both,
|
||||
// that is, logarithm result is typically either all positive or all negative.
|
||||
var moreCountPair = void 0;
|
||||
var mayEnhanceZero = targetExtentInfo.incl0 || isTargetLogScale;
|
||||
// `bounds < 0` or `bounds > 0` may require more complex handling, so we only auto handle
|
||||
// `bounds === 0`.
|
||||
if (mayEnhanceZero && targetExtent[0] === 0) {
|
||||
// 0 has been included in extent and all positive.
|
||||
moreCountPair = [0, moreCount];
|
||||
} else if (mayEnhanceZero && targetExtent[1] === 0) {
|
||||
// 0 has been included in extent and all negative.
|
||||
moreCountPair = [moreCount, 0];
|
||||
} else {
|
||||
// Try to center ticks in axis space whenever possible, which is especially preferable
|
||||
// in `LogScale`.
|
||||
var lessHalfCount = mathFloor(moreCount / 2);
|
||||
moreCountPair = moreCount % 2 === 0 ? [lessHalfCount, lessHalfCount] : min + max < targetExtent[0] + targetExtent[1] ? [lessHalfCount, lessHalfCount + 1] : [lessHalfCount + 1, lessHalfCount];
|
||||
}
|
||||
minNice = round(minNice - interval * moreCountPair[0], intervalPrecision);
|
||||
maxNice = round(maxNice + interval * moreCountPair[1], intervalPrecision);
|
||||
updateMinFromMinNice();
|
||||
updateMaxFromMaxNice();
|
||||
if (min <= targetExtent[0] && max >= targetExtent[1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
updateIntervalOrLogScaleForNiceOrAligned(targetScale, targetMinMaxFixed, targetOldIntervalExtent, [min, max], targetOldOutermostExtent, {
|
||||
// NOTE: Even in LogScale, `interval` should not be in log space.
|
||||
interval: interval,
|
||||
// Force ticks count, otherwise cumulative error may cause more unexpected ticks to be generated.
|
||||
// Though the overlapping tick labels may be auto-ignored, but probably unexpected, e.g., the min
|
||||
// tick label is ignored but the secondary min tick label is shown, which is unexpected when
|
||||
// `axis.min` is user-specified or dataZoom-specified.
|
||||
intervalCount: alignToNiceSegCount,
|
||||
intervalPrecision: intervalPrecision,
|
||||
niceExtent: [minNice, maxNice]
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
targetScale.freeze();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user