first commit

This commit is contained in:
2026-02-06 20:21:10 +08:00
commit f9d7f980bb
3994 changed files with 1146030 additions and 0 deletions
+325
View File
@@ -0,0 +1,325 @@
/*
* 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 { __extends } from "tslib";
import * as numberUtil from '../util/number.js';
import * as formatUtil from '../util/format.js';
import Scale from './Scale.js';
import * as helper from './helper.js';
import { getScaleBreakHelper } from './break.js';
var roundNumber = numberUtil.round;
var IntervalScale = /** @class */function (_super) {
__extends(IntervalScale, _super);
function IntervalScale() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = 'interval';
// Step is calculated in adjustExtent.
_this._interval = 0;
_this._intervalPrecision = 2;
return _this;
}
IntervalScale.prototype.parse = function (val) {
// `Scale#parse` (and its overrids) are typically applied at the axis values input
// in echarts option. e.g., `axis.min/max`, `dataZoom.min/max`, etc.
// but `series.data` is not included, which uses `dataValueHelper.ts`#`parseDataValue`.
// `Scale#parse` originally introduced in fb8c813215098b9d2458966229bb95c510883d5e
// at 2016 for dataZoom start/end settings (See `parseAxisModelMinMax`).
//
// Historically `scale/Interval.ts` returns the input value directly. But numeric
// values (such as a number-like string '123') effectively passed through here and
// were involved in calculations, which was error-prone and inconsistent with the
// declared TS return type. Previously such issues are fixed separately in different
// places case by case (such as #2475).
//
// Now, we perform actual parse to ensure its `number` type here. The parsing rule
// follows the series data parsing rule (`dataValueHelper.ts`#`parseDataValue`)
// and maintains compatibility as much as possible (thus a more strict parsing
// `number.ts`#`numericToNumber` is not used here.)
//
// FIXME: `ScaleDataValue` also need to be modified to include numeric string type,
// since it effectively does.
return val == null || val === '' ? NaN
// If string (like '-'), using '+' parse to NaN
// If object, also parse to NaN
: Number(val);
};
IntervalScale.prototype.contain = function (val) {
return helper.contain(val, this._extent);
};
IntervalScale.prototype.normalize = function (val) {
return this._calculator.normalize(val, this._extent);
};
IntervalScale.prototype.scale = function (val) {
return this._calculator.scale(val, this._extent);
};
IntervalScale.prototype.getInterval = function () {
return this._interval;
};
IntervalScale.prototype.setInterval = function (interval) {
this._interval = interval;
// Dropped auto calculated niceExtent and use user-set extent.
// We assume user wants to set both interval, min, max to get a better result.
this._niceExtent = this._extent.slice();
this._intervalPrecision = helper.getIntervalPrecision(interval);
};
/**
* @override
*/
IntervalScale.prototype.getTicks = function (opt) {
opt = opt || {};
var interval = this._interval;
var extent = this._extent;
var niceTickExtent = this._niceExtent;
var intervalPrecision = this._intervalPrecision;
var scaleBreakHelper = getScaleBreakHelper();
var ticks = [];
// If interval is 0, return [];
if (!interval) {
return ticks;
}
if (opt.breakTicks === 'only_break' && scaleBreakHelper) {
scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent);
return ticks;
}
// Consider this case: using dataZoom toolbox, zoom and zoom.
var safeLimit = 10000;
if (extent[0] < niceTickExtent[0]) {
if (opt.expandToNicedExtent) {
ticks.push({
value: roundNumber(niceTickExtent[0] - interval, intervalPrecision)
});
} else {
ticks.push({
value: extent[0]
});
}
}
var estimateNiceMultiple = function (tickVal, targetTick) {
return Math.round((targetTick - tickVal) / interval);
};
var tick = niceTickExtent[0];
while (tick <= niceTickExtent[1]) {
ticks.push({
value: tick
});
// Avoid rounding error
tick = roundNumber(tick + interval, intervalPrecision);
if (this._brkCtx) {
var moreMultiple = this._brkCtx.calcNiceTickMultiple(tick, estimateNiceMultiple);
if (moreMultiple >= 0) {
tick = roundNumber(tick + moreMultiple * interval, intervalPrecision);
}
}
if (ticks.length > 0 && tick === ticks[ticks.length - 1].value) {
// Consider out of safe float point, e.g.,
// -3711126.9907707 + 2e-10 === -3711126.9907707
break;
}
if (ticks.length > safeLimit) {
return [];
}
}
// Consider this case: the last item of ticks is smaller
// than niceTickExtent[1] and niceTickExtent[1] === extent[1].
var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1];
if (extent[1] > lastNiceTick) {
if (opt.expandToNicedExtent) {
ticks.push({
value: roundNumber(lastNiceTick + interval, intervalPrecision)
});
} else {
ticks.push({
value: extent[1]
});
}
}
if (scaleBreakHelper) {
scaleBreakHelper.pruneTicksByBreak(opt.pruneByBreak, ticks, this._brkCtx.breaks, function (item) {
return item.value;
}, this._interval, this._extent);
}
if (opt.breakTicks !== 'none' && scaleBreakHelper) {
scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent);
}
return ticks;
};
IntervalScale.prototype.getMinorTicks = function (splitNumber) {
var ticks = this.getTicks({
expandToNicedExtent: true
});
// NOTE: In log-scale, do not support minor ticks when breaks exist.
// because currently log-scale minor ticks is calculated based on raw values
// rather than log-transformed value, due to an odd effect when breaks exist.
var minorTicks = [];
var extent = this.getExtent();
for (var i = 1; i < ticks.length; i++) {
var nextTick = ticks[i];
var prevTick = ticks[i - 1];
if (prevTick["break"] || nextTick["break"]) {
// Do not build minor ticks to the adjacent ticks to breaks ticks,
// since the interval might be irregular.
continue;
}
var count = 0;
var minorTicksGroup = [];
var interval = nextTick.value - prevTick.value;
var minorInterval = interval / splitNumber;
var minorIntervalPrecision = helper.getIntervalPrecision(minorInterval);
while (count < splitNumber - 1) {
var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval, minorIntervalPrecision);
// For the first and last interval. The count may be less than splitNumber.
if (minorTick > extent[0] && minorTick < extent[1]) {
minorTicksGroup.push(minorTick);
}
count++;
}
var scaleBreakHelper = getScaleBreakHelper();
scaleBreakHelper && scaleBreakHelper.pruneTicksByBreak('auto', minorTicksGroup, this._getNonTransBreaks(), function (value) {
return value;
}, this._interval, extent);
minorTicks.push(minorTicksGroup);
}
return minorTicks;
};
IntervalScale.prototype._getNonTransBreaks = function () {
return this._brkCtx ? this._brkCtx.breaks : [];
};
/**
* @param opt.precision If 'auto', use nice presision.
* @param opt.pad returns 1.50 but not 1.5 if precision is 2.
*/
IntervalScale.prototype.getLabel = function (data, opt) {
if (data == null) {
return '';
}
var precision = opt && opt.precision;
if (precision == null) {
precision = numberUtil.getPrecision(data.value) || 0;
} else if (precision === 'auto') {
// Should be more precise then tick.
precision = this._intervalPrecision;
}
// (1) If `precision` is set, 12.005 should be display as '12.00500'.
// (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.
var dataNum = roundNumber(data.value, precision, true);
return formatUtil.addCommas(dataNum);
};
/**
* FIXME: refactor - disallow override, use composition instead.
*
* The override of `calcNiceTicks` should ensure these members are provided:
* this._intervalPrecision
* this._interval
*
* @param splitNumber By default `5`.
*/
IntervalScale.prototype.calcNiceTicks = function (splitNumber, minInterval, maxInterval) {
splitNumber = splitNumber || 5;
var extent = this._extent.slice();
var span = this._getExtentSpanWithBreaks();
if (!isFinite(span)) {
return;
}
// User may set axis min 0 and data are all negative
// FIXME If it needs to reverse ?
if (span < 0) {
span = -span;
extent.reverse();
this._innerSetExtent(extent[0], extent[1]);
extent = this._extent.slice();
}
var result = helper.intervalScaleNiceTicks(extent, span, splitNumber, minInterval, maxInterval);
this._intervalPrecision = result.intervalPrecision;
this._interval = result.interval;
this._niceExtent = result.niceTickExtent;
};
IntervalScale.prototype.calcNiceExtent = function (opt) {
var extent = this._extent.slice();
// If extent start and end are same, expand them
if (extent[0] === extent[1]) {
if (extent[0] !== 0) {
// Expand extent
// Note that extents can be both negative. See #13154
var expandSize = Math.abs(extent[0]);
// In the fowllowing case
// Axis has been fixed max 100
// Plus data are all 100 and axis extent are [100, 100].
// Extend to the both side will cause expanded max is larger than fixed max.
// So only expand to the smaller side.
if (!opt.fixMax) {
extent[1] += expandSize / 2;
extent[0] -= expandSize / 2;
} else {
extent[0] -= expandSize / 2;
}
} else {
extent[1] = 1;
}
}
var span = extent[1] - extent[0];
// If there are no data and extent are [Infinity, -Infinity]
if (!isFinite(span)) {
extent[0] = 0;
extent[1] = 1;
}
this._innerSetExtent(extent[0], extent[1]);
extent = this._extent.slice();
this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
var interval = this._interval;
var intervalPrecition = this._intervalPrecision;
if (!opt.fixMin) {
extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval, intervalPrecition);
}
if (!opt.fixMax) {
extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval, intervalPrecition);
}
this._innerSetExtent(extent[0], extent[1]);
};
IntervalScale.prototype.setNiceExtent = function (min, max) {
this._niceExtent = [min, max];
};
IntervalScale.type = 'interval';
return IntervalScale;
}(Scale);
Scale.registerClass(IntervalScale);
export default IntervalScale;
+192
View File
@@ -0,0 +1,192 @@
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import Scale from './Scale.js';
import * as numberUtil from '../util/number.js';
// Use some method of IntervalScale
import IntervalScale from './Interval.js';
import { getIntervalPrecision, logTransform } from './helper.js';
import { getScaleBreakHelper } from './break.js';
var fixRound = numberUtil.round;
var mathFloor = Math.floor;
var mathCeil = Math.ceil;
var mathPow = Math.pow;
var mathLog = Math.log;
var LogScale = /** @class */function (_super) {
__extends(LogScale, _super);
function LogScale() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = 'log';
_this.base = 10;
_this._originalScale = new IntervalScale();
return _this;
}
/**
* @param Whether expand the ticks to niced extent.
*/
LogScale.prototype.getTicks = function (opt) {
opt = opt || {};
var extent = this._extent.slice();
var originalExtent = this._originalScale.getExtent();
var ticks = _super.prototype.getTicks.call(this, opt);
var base = this.base;
var originalBreaks = this._originalScale._innerGetBreaks();
var scaleBreakHelper = getScaleBreakHelper();
return zrUtil.map(ticks, function (tick) {
var val = tick.value;
var roundingCriterion = null;
var powVal = mathPow(base, val);
// Fix #4158
if (val === extent[0] && this._fixMin) {
roundingCriterion = originalExtent[0];
} else if (val === extent[1] && this._fixMax) {
roundingCriterion = originalExtent[1];
}
var vBreak;
if (scaleBreakHelper) {
var transformed = scaleBreakHelper.getTicksLogTransformBreak(tick, base, originalBreaks, fixRoundingError);
vBreak = transformed.vBreak;
if (roundingCriterion == null) {
roundingCriterion = transformed.brkRoundingCriterion;
}
}
if (roundingCriterion != null) {
powVal = fixRoundingError(powVal, roundingCriterion);
}
return {
value: powVal,
"break": vBreak
};
}, this);
};
LogScale.prototype._getNonTransBreaks = function () {
return this._originalScale._innerGetBreaks();
};
LogScale.prototype.setExtent = function (start, end) {
this._originalScale.setExtent(start, end);
var loggedExtent = logTransform(this.base, [start, end]);
_super.prototype.setExtent.call(this, loggedExtent[0], loggedExtent[1]);
};
/**
* @return {number} end
*/
LogScale.prototype.getExtent = function () {
var base = this.base;
var extent = _super.prototype.getExtent.call(this);
extent[0] = mathPow(base, extent[0]);
extent[1] = mathPow(base, extent[1]);
// Fix #4158
var originalExtent = this._originalScale.getExtent();
this._fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));
this._fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));
return extent;
};
LogScale.prototype.unionExtentFromData = function (data, dim) {
this._originalScale.unionExtentFromData(data, dim);
var loggedOther = logTransform(this.base, data.getApproximateExtent(dim), true);
this._innerUnionExtent(loggedOther);
};
/**
* Update interval and extent of intervals for nice ticks
* @param approxTickNum default 10 Given approx tick number
*/
LogScale.prototype.calcNiceTicks = function (approxTickNum) {
approxTickNum = approxTickNum || 10;
var extent = this._extent.slice();
var span = this._getExtentSpanWithBreaks();
if (!isFinite(span) || span <= 0) {
return;
}
var interval = numberUtil.quantity(span);
var err = approxTickNum / span * interval;
// Filter ticks to get closer to the desired count.
if (err <= 0.5) {
interval *= 10;
}
// Interval should be integer
while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {
interval *= 10;
}
var niceExtent = [fixRound(mathCeil(extent[0] / interval) * interval), fixRound(mathFloor(extent[1] / interval) * interval)];
this._interval = interval;
this._intervalPrecision = getIntervalPrecision(interval);
this._niceExtent = niceExtent;
};
LogScale.prototype.calcNiceExtent = function (opt) {
_super.prototype.calcNiceExtent.call(this, opt);
this._fixMin = opt.fixMin;
this._fixMax = opt.fixMax;
};
LogScale.prototype.contain = function (val) {
val = mathLog(val) / mathLog(this.base);
return _super.prototype.contain.call(this, val);
};
LogScale.prototype.normalize = function (val) {
val = mathLog(val) / mathLog(this.base);
return _super.prototype.normalize.call(this, val);
};
LogScale.prototype.scale = function (val) {
val = _super.prototype.scale.call(this, val);
return mathPow(this.base, val);
};
LogScale.prototype.setBreaksFromOption = function (breakOptionList) {
var scaleBreakHelper = getScaleBreakHelper();
if (!scaleBreakHelper) {
return;
}
var _a = scaleBreakHelper.logarithmicParseBreaksFromOption(breakOptionList, this.base, zrUtil.bind(this.parse, this)),
parsedOriginal = _a.parsedOriginal,
parsedLogged = _a.parsedLogged;
this._originalScale._innerSetBreak(parsedOriginal);
this._innerSetBreak(parsedLogged);
};
LogScale.type = 'log';
return LogScale;
}(IntervalScale);
function fixRoundingError(val, originalVal) {
return fixRound(val, numberUtil.getPrecision(originalVal));
}
Scale.registerClass(LogScale);
export default LogScale;
+210
View File
@@ -0,0 +1,210 @@
/*
* 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 { __extends } from "tslib";
/**
* Linear continuous scale
* http://en.wikipedia.org/wiki/Level_of_measurement
*/
// FIXME only one data
import Scale from './Scale.js';
import OrdinalMeta from '../data/OrdinalMeta.js';
import * as scaleHelper from './helper.js';
import { isArray, map, isObject, isString } from 'zrender/lib/core/util.js';
var OrdinalScale = /** @class */function (_super) {
__extends(OrdinalScale, _super);
function OrdinalScale(setting) {
var _this = _super.call(this, setting) || this;
_this.type = 'ordinal';
var ordinalMeta = _this.getSetting('ordinalMeta');
// Caution: Should not use instanceof, consider ec-extensions using
// import approach to get OrdinalMeta class.
if (!ordinalMeta) {
ordinalMeta = new OrdinalMeta({});
}
if (isArray(ordinalMeta)) {
ordinalMeta = new OrdinalMeta({
categories: map(ordinalMeta, function (item) {
return isObject(item) ? item.value : item;
})
});
}
_this._ordinalMeta = ordinalMeta;
_this._extent = _this.getSetting('extent') || [0, ordinalMeta.categories.length - 1];
return _this;
}
OrdinalScale.prototype.parse = function (val) {
// Caution: Math.round(null) will return `0` rather than `NaN`
if (val == null) {
return NaN;
}
return isString(val) ? this._ordinalMeta.getOrdinal(val)
// val might be float.
: Math.round(val);
};
OrdinalScale.prototype.contain = function (val) {
return scaleHelper.contain(val, this._extent) && val >= 0 && val < this._ordinalMeta.categories.length;
};
/**
* Normalize given rank or name to linear [0, 1]
* @param val raw ordinal number.
* @return normalized value in [0, 1].
*/
OrdinalScale.prototype.normalize = function (val) {
val = this._getTickNumber(val);
return this._calculator.normalize(val, this._extent);
};
/**
* @param val normalized value in [0, 1].
* @return raw ordinal number.
*/
OrdinalScale.prototype.scale = function (val) {
val = Math.round(this._calculator.scale(val, this._extent));
return this.getRawOrdinalNumber(val);
};
OrdinalScale.prototype.getTicks = function () {
var ticks = [];
var extent = this._extent;
var rank = extent[0];
while (rank <= extent[1]) {
ticks.push({
value: rank
});
rank++;
}
return ticks;
};
OrdinalScale.prototype.getMinorTicks = function (splitNumber) {
// Not support.
return;
};
/**
* @see `Ordinal['_ordinalNumbersByTick']`
*/
OrdinalScale.prototype.setSortInfo = function (info) {
if (info == null) {
this._ordinalNumbersByTick = this._ticksByOrdinalNumber = null;
return;
}
var infoOrdinalNumbers = info.ordinalNumbers;
var ordinalsByTick = this._ordinalNumbersByTick = [];
var ticksByOrdinal = this._ticksByOrdinalNumber = [];
// Unnecessary support negative tick in `realtimeSort`.
var tickNum = 0;
var allCategoryLen = this._ordinalMeta.categories.length;
for (var len = Math.min(allCategoryLen, infoOrdinalNumbers.length); tickNum < len; ++tickNum) {
var ordinalNumber = infoOrdinalNumbers[tickNum];
ordinalsByTick[tickNum] = ordinalNumber;
ticksByOrdinal[ordinalNumber] = tickNum;
}
// Handle that `series.data` only covers part of the `axis.category.data`.
var unusedOrdinal = 0;
for (; tickNum < allCategoryLen; ++tickNum) {
while (ticksByOrdinal[unusedOrdinal] != null) {
unusedOrdinal++;
}
;
ordinalsByTick.push(unusedOrdinal);
ticksByOrdinal[unusedOrdinal] = tickNum;
}
};
OrdinalScale.prototype._getTickNumber = function (ordinal) {
var ticksByOrdinalNumber = this._ticksByOrdinalNumber;
// also support ordinal out of range of `ordinalMeta.categories.length`,
// where ordinal numbers are used as tick value directly.
return ticksByOrdinalNumber && ordinal >= 0 && ordinal < ticksByOrdinalNumber.length ? ticksByOrdinalNumber[ordinal] : ordinal;
};
/**
* @usage
* ```js
* const ordinalNumber = ordinalScale.getRawOrdinalNumber(tickVal);
*
* // case0
* const rawOrdinalValue = axisModel.getCategories()[ordinalNumber];
* // case1
* const rawOrdinalValue = this._ordinalMeta.categories[ordinalNumber];
* // case2
* const coord = axis.dataToCoord(ordinalNumber);
* ```
*
* @param {OrdinalNumber} tickNumber index of display
*/
OrdinalScale.prototype.getRawOrdinalNumber = function (tickNumber) {
var ordinalNumbersByTick = this._ordinalNumbersByTick;
// tickNumber may be out of range, e.g., when axis max is larger than `ordinalMeta.categories.length`.,
// where ordinal numbers are used as tick value directly.
return ordinalNumbersByTick && tickNumber >= 0 && tickNumber < ordinalNumbersByTick.length ? ordinalNumbersByTick[tickNumber] : tickNumber;
};
/**
* Get item on tick
*/
OrdinalScale.prototype.getLabel = function (tick) {
if (!this.isBlank()) {
var ordinalNumber = this.getRawOrdinalNumber(tick.value);
var cateogry = this._ordinalMeta.categories[ordinalNumber];
// Note that if no data, ordinalMeta.categories is an empty array.
// Return empty if it's not exist.
return cateogry == null ? '' : cateogry + '';
}
};
OrdinalScale.prototype.count = function () {
return this._extent[1] - this._extent[0] + 1;
};
/**
* @override
* If value is in extent range
*/
OrdinalScale.prototype.isInExtentRange = function (value) {
value = this._getTickNumber(value);
return this._extent[0] <= value && this._extent[1] >= value;
};
OrdinalScale.prototype.getOrdinalMeta = function () {
return this._ordinalMeta;
};
OrdinalScale.prototype.calcNiceTicks = function () {};
OrdinalScale.prototype.calcNiceExtent = function () {};
OrdinalScale.type = 'ordinal';
return OrdinalScale;
}(Scale);
Scale.registerClass(OrdinalScale);
export default OrdinalScale;
+156
View File
@@ -0,0 +1,156 @@
/*
* 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 * as clazzUtil from '../util/clazz.js';
import { ScaleCalculator } from './helper.js';
import { bind } from 'zrender/lib/core/util.js';
import { getScaleBreakHelper } from './break.js';
var Scale = /** @class */function () {
function Scale(setting) {
this._calculator = new ScaleCalculator();
this._setting = setting || {};
this._extent = [Infinity, -Infinity];
var scaleBreakHelper = getScaleBreakHelper();
if (scaleBreakHelper) {
this._brkCtx = scaleBreakHelper.createScaleBreakContext();
this._brkCtx.update(this._extent);
}
}
Scale.prototype.getSetting = function (name) {
return this._setting[name];
};
/**
* [CAVEAT]: It should not be overridden!
*/
Scale.prototype._innerUnionExtent = function (other) {
var extent = this._extent;
// Considered that number could be NaN and should not write into the extent.
this._innerSetExtent(other[0] < extent[0] ? other[0] : extent[0], other[1] > extent[1] ? other[1] : extent[1]);
};
/**
* Set extent from data
*/
Scale.prototype.unionExtentFromData = function (data, dim) {
this._innerUnionExtent(data.getApproximateExtent(dim));
};
/**
* Get a new slice of extent.
* Extent is always in increase order.
*/
Scale.prototype.getExtent = function () {
return this._extent.slice();
};
Scale.prototype.setExtent = function (start, end) {
this._innerSetExtent(start, end);
};
/**
* [CAVEAT]: It should not be overridden!
*/
Scale.prototype._innerSetExtent = function (start, end) {
var thisExtent = this._extent;
if (!isNaN(start)) {
thisExtent[0] = start;
}
if (!isNaN(end)) {
thisExtent[1] = end;
}
this._brkCtx && this._brkCtx.update(thisExtent);
};
/**
* Prerequisite: Scale#parse is ready.
*/
Scale.prototype.setBreaksFromOption = function (breakOptionList) {
var scaleBreakHelper = getScaleBreakHelper();
if (scaleBreakHelper) {
this._innerSetBreak(scaleBreakHelper.parseAxisBreakOption(breakOptionList, bind(this.parse, this)));
}
};
/**
* [CAVEAT]: It should not be overridden!
*/
Scale.prototype._innerSetBreak = function (parsed) {
if (this._brkCtx) {
this._brkCtx.setBreaks(parsed);
this._calculator.updateMethods(this._brkCtx);
this._brkCtx.update(this._extent);
}
};
/**
* [CAVEAT]: It should not be overridden!
*/
Scale.prototype._innerGetBreaks = function () {
return this._brkCtx ? this._brkCtx.breaks : [];
};
/**
* Do not expose the internal `_breaks` unless necessary.
*/
Scale.prototype.hasBreaks = function () {
return this._brkCtx ? this._brkCtx.hasBreaks() : false;
};
Scale.prototype._getExtentSpanWithBreaks = function () {
return this._brkCtx && this._brkCtx.hasBreaks() ? this._brkCtx.getExtentSpan() : this._extent[1] - this._extent[0];
};
/**
* If value is in extent range
*/
Scale.prototype.isInExtentRange = function (value) {
return this._extent[0] <= value && this._extent[1] >= value;
};
/**
* When axis extent depends on data and no data exists,
* axis ticks should not be drawn, which is named 'blank'.
*/
Scale.prototype.isBlank = function () {
return this._isBlank;
};
/**
* When axis extent depends on data and no data exists,
* axis ticks should not be drawn, which is named 'blank'.
*/
Scale.prototype.setBlank = function (isBlank) {
this._isBlank = isBlank;
};
return Scale;
}();
clazzUtil.enableClassManagement(Scale);
export default Scale;
+568
View File
@@ -0,0 +1,568 @@
/*
* 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 { __extends } from "tslib";
/*
* A third-party license is embedded for some of the code in this file:
* The "scaleLevels" was originally copied from "d3.js" with some
* modifications made for this project.
* (See more details in the comment on the definition of "scaleLevels" below.)
* The use of the source code of this file is also subject to the terms
* and consitions of the license of "d3.js" (BSD-3Clause, see
* </licenses/LICENSE-d3>).
*/
// [About UTC and local time zone]:
// In most cases, `number.parseDate` will treat input data string as local time
// (except time zone is specified in time string). And `format.formateTime` returns
// local time by default. option.useUTC is false by default. This design has
// considered these common cases:
// (1) Time that is persistent in server is in UTC, but it is needed to be displayed
// in local time by default.
// (2) By default, the input data string (e.g., '2011-01-02') should be displayed
// as its original time, without any time difference.
import * as numberUtil from '../util/number.js';
import { ONE_SECOND, ONE_MINUTE, ONE_HOUR, ONE_DAY, ONE_YEAR, format, leveledFormat, timeUnits, fullLeveledFormatter, getPrimaryTimeUnit, isPrimaryTimeUnit, getDefaultFormatPrecisionOfInterval, fullYearGetterName, monthSetterName, fullYearSetterName, dateSetterName, hoursGetterName, hoursSetterName, minutesSetterName, secondsSetterName, millisecondsSetterName, monthGetterName, dateGetterName, minutesGetterName, secondsGetterName, millisecondsGetterName, getUnitFromValue, primaryTimeUnits, roundTime } from '../util/time.js';
import * as scaleHelper from './helper.js';
import IntervalScale from './Interval.js';
import Scale from './Scale.js';
import { warn } from '../util/log.js';
import { each, filter, indexOf, isNumber, map } from 'zrender/lib/core/util.js';
import { getScaleBreakHelper } from './break.js';
// FIXME 公用?
var bisect = function (a, x, lo, hi) {
while (lo < hi) {
var mid = lo + hi >>> 1;
if (a[mid][1] < x) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
};
var TimeScale = /** @class */function (_super) {
__extends(TimeScale, _super);
function TimeScale(settings) {
var _this = _super.call(this, settings) || this;
_this.type = 'time';
return _this;
}
/**
* Get label is mainly for other components like dataZoom, tooltip.
*/
TimeScale.prototype.getLabel = function (tick) {
var useUTC = this.getSetting('useUTC');
return format(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC, this.getSetting('locale'));
};
TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) {
var isUTC = this.getSetting('useUTC');
var lang = this.getSetting('locale');
return leveledFormat(tick, idx, labelFormatter, lang, isUTC);
};
/**
* @override
*/
TimeScale.prototype.getTicks = function (opt) {
opt = opt || {};
var interval = this._interval;
var extent = this._extent;
var scaleBreakHelper = getScaleBreakHelper();
var ticks = [];
// If interval is 0, return [];
if (!interval) {
return ticks;
}
var useUTC = this.getSetting('useUTC');
if (scaleBreakHelper && opt.breakTicks === 'only_break') {
getScaleBreakHelper().addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent);
return ticks;
}
var extent0Unit = getUnitFromValue(extent[1], useUTC);
ticks.push({
value: extent[0],
time: {
level: 0,
upperTimeUnit: extent0Unit,
lowerTimeUnit: extent0Unit
}
});
var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent, this._getExtentSpanWithBreaks(), this._brkCtx);
ticks = ticks.concat(innerTicks);
var extent1Unit = getUnitFromValue(extent[1], useUTC);
ticks.push({
value: extent[1],
time: {
level: 0,
upperTimeUnit: extent1Unit,
lowerTimeUnit: extent1Unit
}
});
var isUTC = this.getSetting('useUTC');
var upperUnitIndex = primaryTimeUnits.length - 1;
var maxLevel = 0;
each(ticks, function (tick) {
upperUnitIndex = Math.min(upperUnitIndex, indexOf(primaryTimeUnits, tick.time.upperTimeUnit));
maxLevel = Math.max(maxLevel, tick.time.level);
});
if (scaleBreakHelper) {
getScaleBreakHelper().pruneTicksByBreak(opt.pruneByBreak, ticks, this._brkCtx.breaks, function (item) {
return item.value;
}, this._approxInterval, this._extent);
}
if (scaleBreakHelper && opt.breakTicks !== 'none') {
getScaleBreakHelper().addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent, function (trimmedBrk) {
// @see `parseTimeAxisLabelFormatterDictionary`.
var lowerBrkUnitIndex = Math.max(indexOf(primaryTimeUnits, getUnitFromValue(trimmedBrk.vmin, isUTC)), indexOf(primaryTimeUnits, getUnitFromValue(trimmedBrk.vmax, isUTC)));
var upperBrkUnitIndex = 0;
for (var unitIdx = 0; unitIdx < primaryTimeUnits.length; unitIdx++) {
if (!isPrimaryUnitValueAndGreaterSame(primaryTimeUnits[unitIdx], trimmedBrk.vmin, trimmedBrk.vmax, isUTC)) {
upperBrkUnitIndex = unitIdx;
break;
}
}
var upperIdx = Math.min(upperBrkUnitIndex, upperUnitIndex);
var lowerIdx = Math.max(upperIdx, lowerBrkUnitIndex);
return {
level: maxLevel,
lowerTimeUnit: primaryTimeUnits[lowerIdx],
upperTimeUnit: primaryTimeUnits[upperIdx]
};
});
}
return ticks;
};
TimeScale.prototype.calcNiceExtent = function (opt) {
var extent = this.getExtent();
// If extent start and end are same, expand them
if (extent[0] === extent[1]) {
// Expand extent
extent[0] -= ONE_DAY;
extent[1] += ONE_DAY;
}
// If there are no data and extent are [Infinity, -Infinity]
if (extent[1] === -Infinity && extent[0] === Infinity) {
var d = new Date();
extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());
extent[0] = extent[1] - ONE_DAY;
}
this._innerSetExtent(extent[0], extent[1]);
this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
};
TimeScale.prototype.calcNiceTicks = function (approxTickNum, minInterval, maxInterval) {
approxTickNum = approxTickNum || 10;
var span = this._getExtentSpanWithBreaks();
this._approxInterval = span / approxTickNum;
if (minInterval != null && this._approxInterval < minInterval) {
this._approxInterval = minInterval;
}
if (maxInterval != null && this._approxInterval > maxInterval) {
this._approxInterval = maxInterval;
}
var scaleIntervalsLen = scaleIntervals.length;
var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1);
// Interval that can be used to calculate ticks
this._interval = scaleIntervals[idx][1];
this._intervalPrecision = scaleHelper.getIntervalPrecision(this._interval);
// Min level used when picking ticks from top down.
// We check one more level to avoid the ticks are to sparse in some case.
this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0];
};
TimeScale.prototype.parse = function (val) {
// val might be float.
return isNumber(val) ? val : +numberUtil.parseDate(val);
};
TimeScale.prototype.contain = function (val) {
return scaleHelper.contain(val, this._extent);
};
TimeScale.prototype.normalize = function (val) {
return this._calculator.normalize(val, this._extent);
};
TimeScale.prototype.scale = function (val) {
return this._calculator.scale(val, this._extent);
};
TimeScale.type = 'time';
return TimeScale;
}(IntervalScale);
/**
* This implementation was originally copied from "d3.js"
* <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>
* with some modifications made for this program.
* See the license statement at the head of this file.
*/
var scaleIntervals = [
// Format interval
['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR] // 1Y
];
function isPrimaryUnitValueAndGreaterSame(unit, valueA, valueB, isUTC) {
return roundTime(new Date(valueA), unit, isUTC).getTime() === roundTime(new Date(valueB), unit, isUTC).getTime();
}
// function isUnitValueSame(
// unit: PrimaryTimeUnit,
// valueA: number,
// valueB: number,
// isUTC: boolean
// ): boolean {
// const dateA = numberUtil.parseDate(valueA) as any;
// const dateB = numberUtil.parseDate(valueB) as any;
// const isSame = (unit: PrimaryTimeUnit) => {
// return getUnitValue(dateA, unit, isUTC)
// === getUnitValue(dateB, unit, isUTC);
// };
// const isSameYear = () => isSame('year');
// // const isSameHalfYear = () => isSameYear() && isSame('half-year');
// // const isSameQuater = () => isSameYear() && isSame('quarter');
// const isSameMonth = () => isSameYear() && isSame('month');
// const isSameDay = () => isSameMonth() && isSame('day');
// // const isSameHalfDay = () => isSameDay() && isSame('half-day');
// const isSameHour = () => isSameDay() && isSame('hour');
// const isSameMinute = () => isSameHour() && isSame('minute');
// const isSameSecond = () => isSameMinute() && isSame('second');
// const isSameMilliSecond = () => isSameSecond() && isSame('millisecond');
// switch (unit) {
// case 'year':
// return isSameYear();
// case 'month':
// return isSameMonth();
// case 'day':
// return isSameDay();
// case 'hour':
// return isSameHour();
// case 'minute':
// return isSameMinute();
// case 'second':
// return isSameSecond();
// case 'millisecond':
// return isSameMilliSecond();
// }
// }
// const primaryUnitGetters = {
// year: fullYearGetterName(),
// month: monthGetterName(),
// day: dateGetterName(),
// hour: hoursGetterName(),
// minute: minutesGetterName(),
// second: secondsGetterName(),
// millisecond: millisecondsGetterName()
// };
// const primaryUnitUTCGetters = {
// year: fullYearGetterName(true),
// month: monthGetterName(true),
// day: dateGetterName(true),
// hour: hoursGetterName(true),
// minute: minutesGetterName(true),
// second: secondsGetterName(true),
// millisecond: millisecondsGetterName(true)
// };
// function moveTick(date: Date, unitName: TimeUnit, step: number, isUTC: boolean) {
// step = step || 1;
// switch (getPrimaryTimeUnit(unitName)) {
// case 'year':
// date[fullYearSetterName(isUTC)](date[fullYearGetterName(isUTC)]() + step);
// break;
// case 'month':
// date[monthSetterName(isUTC)](date[monthGetterName(isUTC)]() + step);
// break;
// case 'day':
// date[dateSetterName(isUTC)](date[dateGetterName(isUTC)]() + step);
// break;
// case 'hour':
// date[hoursSetterName(isUTC)](date[hoursGetterName(isUTC)]() + step);
// break;
// case 'minute':
// date[minutesSetterName(isUTC)](date[minutesGetterName(isUTC)]() + step);
// break;
// case 'second':
// date[secondsSetterName(isUTC)](date[secondsGetterName(isUTC)]() + step);
// break;
// case 'millisecond':
// date[millisecondsSetterName(isUTC)](date[millisecondsGetterName(isUTC)]() + step);
// break;
// }
// return date.getTime();
// }
// const DATE_INTERVALS = [[8, 7.5], [4, 3.5], [2, 1.5]];
// const MONTH_INTERVALS = [[6, 5.5], [3, 2.5], [2, 1.5]];
// const MINUTES_SECONDS_INTERVALS = [[30, 30], [20, 20], [15, 15], [10, 10], [5, 5], [2, 2]];
function getDateInterval(approxInterval, daysInMonth) {
approxInterval /= ONE_DAY;
return approxInterval > 16 ? 16
// Math.floor(daysInMonth / 2) + 1 // In this case we only want one tick between two months.
: approxInterval > 7.5 ? 7 // TODO week 7 or day 8?
: approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1;
}
function getMonthInterval(approxInterval) {
var APPROX_ONE_MONTH = 30 * ONE_DAY;
approxInterval /= APPROX_ONE_MONTH;
return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1;
}
function getHourInterval(approxInterval) {
approxInterval /= ONE_HOUR;
return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1;
}
function getMinutesAndSecondsInterval(approxInterval, isMinutes) {
approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND;
return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1;
}
function getMillisecondsInterval(approxInterval) {
return numberUtil.nice(approxInterval, true);
}
// e.g., if the input unit is 'day', start calculate ticks from the first day of
// that month to make ticks "nice".
function getFirstTimestampOfUnit(timestamp, unitName, isUTC) {
var upperUnitIdx = Math.max(0, indexOf(primaryTimeUnits, unitName) - 1);
return roundTime(new Date(timestamp), primaryTimeUnits[upperUnitIdx], isUTC).getTime();
}
function createEstimateNiceMultiple(setMethodName, dateMethodInterval) {
var tmpDate = new Date(0);
tmpDate[setMethodName](1);
var tmpTime = tmpDate.getTime();
tmpDate[setMethodName](1 + dateMethodInterval);
var approxTimeInterval = tmpDate.getTime() - tmpTime;
return function (tickVal, targetValue) {
// Only in month that accurate result can not get by division of
// timestamp interval, but no need accurate here.
return Math.max(0, Math.round((targetValue - tickVal) / approxTimeInterval));
};
}
function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent, extentSpanWithBreaks, brkCtx) {
var safeLimit = 10000;
var unitNames = timeUnits;
var iter = 0;
function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) {
var estimateNiceMultiple = createEstimateNiceMultiple(setMethodName, interval);
var dateTime = minTimestamp;
var date = new Date(dateTime);
// if (isDate) {
// d -= 1; // Starts with 0; PENDING
// }
while (dateTime < maxTimestamp && dateTime <= extent[1]) {
out.push({
value: dateTime
});
if (iter++ > safeLimit) {
if (process.env.NODE_ENV !== 'production') {
warn('Exceed safe limit in time scale.');
}
break;
}
date[setMethodName](date[getMethodName]() + interval);
dateTime = date.getTime();
if (brkCtx) {
var moreMultiple = brkCtx.calcNiceTickMultiple(dateTime, estimateNiceMultiple);
if (moreMultiple > 0) {
date[setMethodName](date[getMethodName]() + moreMultiple * interval);
dateTime = date.getTime();
}
}
}
// This extra tick is for calcuating ticks of next level. Will not been added to the final result
out.push({
value: dateTime,
notAdd: true
});
}
function addLevelTicks(unitName, lastLevelTicks, levelTicks) {
var newAddedTicks = [];
var isFirstLevel = !lastLevelTicks.length;
if (isPrimaryUnitValueAndGreaterSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) {
return;
}
if (isFirstLevel) {
lastLevelTicks = [{
value: getFirstTimestampOfUnit(extent[0], unitName, isUTC)
}, {
value: extent[1]
}];
}
for (var i = 0; i < lastLevelTicks.length - 1; i++) {
var startTick = lastLevelTicks[i].value;
var endTick = lastLevelTicks[i + 1].value;
if (startTick === endTick) {
continue;
}
var interval = void 0;
var getterName = void 0;
var setterName = void 0;
var isDate = false;
switch (unitName) {
case 'year':
interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365));
getterName = fullYearGetterName(isUTC);
setterName = fullYearSetterName(isUTC);
break;
case 'half-year':
case 'quarter':
case 'month':
interval = getMonthInterval(approxInterval);
getterName = monthGetterName(isUTC);
setterName = monthSetterName(isUTC);
break;
case 'week': // PENDING If week is added. Ignore day.
case 'half-week':
case 'day':
interval = getDateInterval(approxInterval, 31); // Use 32 days and let interval been 16
getterName = dateGetterName(isUTC);
setterName = dateSetterName(isUTC);
isDate = true;
break;
case 'half-day':
case 'quarter-day':
case 'hour':
interval = getHourInterval(approxInterval);
getterName = hoursGetterName(isUTC);
setterName = hoursSetterName(isUTC);
break;
case 'minute':
interval = getMinutesAndSecondsInterval(approxInterval, true);
getterName = minutesGetterName(isUTC);
setterName = minutesSetterName(isUTC);
break;
case 'second':
interval = getMinutesAndSecondsInterval(approxInterval, false);
getterName = secondsGetterName(isUTC);
setterName = secondsSetterName(isUTC);
break;
case 'millisecond':
interval = getMillisecondsInterval(approxInterval);
getterName = millisecondsGetterName(isUTC);
setterName = millisecondsSetterName(isUTC);
break;
}
// Notice: This expansion by `getFirstTimestampOfUnit` may cause too many ticks and
// iteration. e.g., when three levels of ticks is displayed, which can be caused by
// data zoom and axis breaks. Thus trim them here.
if (endTick >= extent[0] && startTick <= extent[1]) {
addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks);
}
if (unitName === 'year' && levelTicks.length > 1 && i === 0) {
// Add nearest years to the left extent.
levelTicks.unshift({
value: levelTicks[0].value - interval
});
}
}
for (var i = 0; i < newAddedTicks.length; i++) {
levelTicks.push(newAddedTicks[i]);
}
}
var levelsTicks = [];
var currentLevelTicks = [];
var tickCount = 0;
var lastLevelTickCount = 0;
for (var i = 0; i < unitNames.length; ++i) {
var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]);
if (!isPrimaryTimeUnit(unitNames[i])) {
// TODO
continue;
}
addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks);
var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null;
if (primaryTimeUnit !== nextPrimaryTimeUnit) {
if (currentLevelTicks.length) {
lastLevelTickCount = tickCount;
// Remove the duplicate so the tick count can be precisely.
currentLevelTicks.sort(function (a, b) {
return a.value - b.value;
});
var levelTicksRemoveDuplicated = [];
for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) {
var tickValue = currentLevelTicks[i_1].value;
if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) {
levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]);
if (tickValue >= extent[0] && tickValue <= extent[1]) {
tickCount++;
}
}
}
var targetTickNum = extentSpanWithBreaks / approxInterval;
// Added too much in this level and not too less in last level
if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) {
break;
}
// Only treat primary time unit as one level.
levelsTicks.push(levelTicksRemoveDuplicated);
if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) {
break;
}
}
// Reset if next unitName is primary
currentLevelTicks = [];
}
}
var levelsTicksInExtent = filter(map(levelsTicks, function (levelTicks) {
return filter(levelTicks, function (tick) {
return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd;
});
}), function (levelTicks) {
return levelTicks.length > 0;
});
var ticks = [];
var maxLevel = levelsTicksInExtent.length - 1;
for (var i = 0; i < levelsTicksInExtent.length; ++i) {
var levelTicks = levelsTicksInExtent[i];
for (var k = 0; k < levelTicks.length; ++k) {
var unit = getUnitFromValue(levelTicks[k].value, isUTC);
ticks.push({
value: levelTicks[k].value,
time: {
level: maxLevel - i,
upperTimeUnit: unit,
lowerTimeUnit: unit
}
});
}
}
ticks.sort(function (a, b) {
return a.value - b.value;
});
// Remove duplicates
var result = [];
for (var i = 0; i < ticks.length; ++i) {
if (i === 0 || ticks[i].value !== ticks[i - 1].value) {
result.push(ticks[i]);
}
}
return result;
}
Scale.registerClass(TimeScale);
export default TimeScale;
+53
View File
@@ -0,0 +1,53 @@
/*
* 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.
*/
;
var _impl = null;
export function registerScaleBreakHelperImpl(impl) {
if (!_impl) {
_impl = impl;
}
}
export function getScaleBreakHelper() {
return _impl;
}
+639
View File
@@ -0,0 +1,639 @@
/*
* 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, clone, each, find, isString, map, trim } from 'zrender/lib/core/util.js';
import { error } from '../util/log.js';
import { registerScaleBreakHelperImpl } from './break.js';
import { round as fixRound } from '../util/number.js';
/**
* @caution
* Must not export anything except `installScaleBreakHelper`
*/
var ScaleBreakContextImpl = /** @class */function () {
function ScaleBreakContextImpl() {
// [CAVEAT]: Should set only by `ScaleBreakContext#setBreaks`!
this.breaks = [];
// [CAVEAT]: Should update only by `ScaleBreakContext#update`!
// They are the values that scaleExtent[0] and scaleExtent[1] are mapped to a numeric axis
// that breaks are applied, primarily for optimization of `Scale#normalize`.
this._elapsedExtent = [Infinity, -Infinity];
}
ScaleBreakContextImpl.prototype.setBreaks = function (parsed) {
// @ts-ignore
this.breaks = parsed.breaks;
};
/**
* [CAVEAT]: Must be called immediately each time scale extent and breaks are updated!
*/
ScaleBreakContextImpl.prototype.update = function (scaleExtent) {
updateAxisBreakGapReal(this, scaleExtent);
var elapsedExtent = this._elapsedExtent;
elapsedExtent[0] = this.elapse(scaleExtent[0]);
elapsedExtent[1] = this.elapse(scaleExtent[1]);
};
ScaleBreakContextImpl.prototype.hasBreaks = function () {
return !!this.breaks.length;
};
/**
* When iteratively generating ticks by nice interval, currently the `interval`, which is
* calculated by break-elapsed extent span, is probably very small comparing to the original
* extent, leading to a large number of iteration and tick generation, even over `safeLimit`.
* Thus stepping over breaks is necessary in that loop.
*
* "Nice" should be ensured on ticks when step over the breaks. Thus this method returns
* a integer multiple of the "nice tick interval".
*
* This method does little work; it is just for unifying and restricting the behavior.
*/
ScaleBreakContextImpl.prototype.calcNiceTickMultiple = function (tickVal, estimateNiceMultiple) {
for (var idx = 0; idx < this.breaks.length; idx++) {
var brk = this.breaks[idx];
if (brk.vmin < tickVal && tickVal < brk.vmax) {
var multiple = estimateNiceMultiple(tickVal, brk.vmax);
if (process.env.NODE_ENV !== 'production') {
// If not, it may cause dead loop or not nice tick.
assert(multiple >= 0 && Math.round(multiple) === multiple);
}
return multiple;
}
}
return 0;
};
ScaleBreakContextImpl.prototype.getExtentSpan = function () {
return this._elapsedExtent[1] - this._elapsedExtent[0];
};
ScaleBreakContextImpl.prototype.normalize = function (val) {
var elapsedSpan = this._elapsedExtent[1] - this._elapsedExtent[0];
// The same logic as `Scale#normalize`.
if (elapsedSpan === 0) {
return 0.5;
}
return (this.elapse(val) - this._elapsedExtent[0]) / elapsedSpan;
};
ScaleBreakContextImpl.prototype.scale = function (val) {
return this.unelapse(val * (this._elapsedExtent[1] - this._elapsedExtent[0]) + this._elapsedExtent[0]);
};
/**
* Suppose:
* AXIS_BREAK_LAST_BREAK_END_BASE: 0
* AXIS_BREAK_ELAPSED_BASE: 0
* breaks: [
* {start: -400, end: -300, gap: 27},
* {start: -100, end: 100, gap: 10},
* {start: 200, end: 400, gap: 300},
* ]
* The mapping will be:
* | |
* 400 + -> + 237
* | | | | (gap: 300)
* 200 + -> + -63
* | |
* 100 + -> + -163
* | | | | (gap: 10)
* -100 + -> + -173
* | |
* -300 + -> + -373
* | | | | (gap: 27)
* -400 + -> + -400
* | |
* origianl elapsed
*
* Note:
* The mapping has nothing to do with "scale extent".
*/
ScaleBreakContextImpl.prototype.elapse = function (val) {
// If the value is in the break, return the normalized value in the break
var elapsedVal = AXIS_BREAK_ELAPSED_BASE;
var lastBreakEnd = AXIS_BREAK_LAST_BREAK_END_BASE;
var stillOver = true;
for (var i = 0; i < this.breaks.length; i++) {
var brk = this.breaks[i];
if (val <= brk.vmax) {
if (val > brk.vmin) {
elapsedVal += brk.vmin - lastBreakEnd + (val - brk.vmin) / (brk.vmax - brk.vmin) * brk.gapReal;
} else {
elapsedVal += val - lastBreakEnd;
}
lastBreakEnd = brk.vmax;
stillOver = false;
break;
}
elapsedVal += brk.vmin - lastBreakEnd + brk.gapReal;
lastBreakEnd = brk.vmax;
}
if (stillOver) {
elapsedVal += val - lastBreakEnd;
}
return elapsedVal;
};
ScaleBreakContextImpl.prototype.unelapse = function (elapsedVal) {
var lastElapsedEnd = AXIS_BREAK_ELAPSED_BASE;
var lastBreakEnd = AXIS_BREAK_LAST_BREAK_END_BASE;
var stillOver = true;
var unelapsedVal = 0;
for (var i = 0; i < this.breaks.length; i++) {
var brk = this.breaks[i];
var elapsedStart = lastElapsedEnd + brk.vmin - lastBreakEnd;
var elapsedEnd = elapsedStart + brk.gapReal;
if (elapsedVal <= elapsedEnd) {
if (elapsedVal > elapsedStart) {
unelapsedVal = brk.vmin + (elapsedVal - elapsedStart) / (elapsedEnd - elapsedStart) * (brk.vmax - brk.vmin);
} else {
unelapsedVal = lastBreakEnd + elapsedVal - lastElapsedEnd;
}
lastBreakEnd = brk.vmax;
stillOver = false;
break;
}
lastElapsedEnd = elapsedEnd;
lastBreakEnd = brk.vmax;
}
if (stillOver) {
unelapsedVal = lastBreakEnd + elapsedVal - lastElapsedEnd;
}
return unelapsedVal;
};
return ScaleBreakContextImpl;
}();
;
function createScaleBreakContext() {
return new ScaleBreakContextImpl();
}
// Both can start with any finite value, and are not necessaryily equal. But they need to
// be the same in `axisBreakElapse` and `axisBreakUnelapse` respectively.
var AXIS_BREAK_ELAPSED_BASE = 0;
var AXIS_BREAK_LAST_BREAK_END_BASE = 0;
/**
* `gapReal` in brkCtx.breaks will be calculated.
*/
function updateAxisBreakGapReal(brkCtx, scaleExtent) {
// Considered the effect:
// - Use dataZoom to move some of the breaks outside the extent.
// - Some scenarios that `series.clip: false`.
//
// How to calculate `prctBrksGapRealSum`:
// Based on the formula:
// xxx.span = brk.vmax - brk.vmin
// xxx.tpPrct.val / xxx.tpAbs.val means ParsedAxisBreak['gapParsed']['val']
// .S/.E means a break that is semi in scaleExtent[0] or scaleExtent[1]
// valP = (
// + (fullyInExtBrksSum.tpAbs.gapReal - fullyInExtBrksSum.tpAbs.span)
// + (semiInExtBrk.S.tpAbs.gapReal - semiInExtBrk.S.tpAbs.span) * semiInExtBrk.S.tpAbs.inExtFrac
// + (semiInExtBrk.E.tpAbs.gapReal - semiInExtBrk.E.tpAbs.span) * semiInExtBrk.E.tpAbs.inExtFrac
// )
// valQ = (
// - fullyInExtBrksSum.tpPrct.span
// - semiInExtBrk.S.tpPrct.span * semiInExtBrk.S.tpPrct.inExtFrac
// - semiInExtBrk.E.tpPrct.span * semiInExtBrk.E.tpPrct.inExtFrac
// )
// gapPrctSum = sum(xxx.tpPrct.val)
// gapPrctSum = prctBrksGapRealSum / (
// + (scaleExtent[1] - scaleExtent[0]) + valP + valQ
// + fullyInExtBrksSum.tpPrct.gapReal
// + semiInExtBrk.S.tpPrct.gapReal * semiInExtBrk.S.tpPrct.inExtFrac
// + semiInExtBrk.E.tpPrct.gapReal * semiInExtBrk.E.tpPrct.inExtFrac
// )
// Assume:
// xxx.tpPrct.gapReal = xxx.tpPrct.val / gapPrctSum * prctBrksGapRealSum
// (NOTE: This is not accurate when semi-in-extent break exist because its
// proportion is not linear, but this assumption approximately works.)
// Derived as follows:
// prctBrksGapRealSum = gapPrctSum * ( (scaleExtent[1] - scaleExtent[0]) + valP + valQ )
// / (1
// - fullyInExtBrksSum.tpPrct.val
// - semiInExtBrk.S.tpPrct.val * semiInExtBrk.S.tpPrct.inExtFrac
// - semiInExtBrk.E.tpPrct.val * semiInExtBrk.E.tpPrct.inExtFrac
// )
var gapPrctSum = 0;
var fullyInExtBrksSum = {
tpAbs: {
span: 0,
val: 0
},
tpPrct: {
span: 0,
val: 0
}
};
var init = function () {
return {
has: false,
span: NaN,
inExtFrac: NaN,
val: NaN
};
};
var semiInExtBrk = {
S: {
tpAbs: init(),
tpPrct: init()
},
E: {
tpAbs: init(),
tpPrct: init()
}
};
each(brkCtx.breaks, function (brk) {
var gapParsed = brk.gapParsed;
if (gapParsed.type === 'tpPrct') {
gapPrctSum += gapParsed.val;
}
var clampedBrk = clampBreakByExtent(brk, scaleExtent);
if (clampedBrk) {
var vminClamped = clampedBrk.vmin !== brk.vmin;
var vmaxClamped = clampedBrk.vmax !== brk.vmax;
var clampedSpan = clampedBrk.vmax - clampedBrk.vmin;
if (vminClamped && vmaxClamped) {
// Do nothing, which simply makes the result `gapReal` cover the entire scaleExtent.
// This transform is not consistent with the other cases but practically works.
} else if (vminClamped || vmaxClamped) {
var sOrE = vminClamped ? 'S' : 'E';
semiInExtBrk[sOrE][gapParsed.type].has = true;
semiInExtBrk[sOrE][gapParsed.type].span = clampedSpan;
semiInExtBrk[sOrE][gapParsed.type].inExtFrac = clampedSpan / (brk.vmax - brk.vmin);
semiInExtBrk[sOrE][gapParsed.type].val = gapParsed.val;
} else {
fullyInExtBrksSum[gapParsed.type].span += clampedSpan;
fullyInExtBrksSum[gapParsed.type].val += gapParsed.val;
}
}
});
var prctBrksGapRealSum = gapPrctSum * (0 + (scaleExtent[1] - scaleExtent[0]) + (fullyInExtBrksSum.tpAbs.val - fullyInExtBrksSum.tpAbs.span) + (semiInExtBrk.S.tpAbs.has ? (semiInExtBrk.S.tpAbs.val - semiInExtBrk.S.tpAbs.span) * semiInExtBrk.S.tpAbs.inExtFrac : 0) + (semiInExtBrk.E.tpAbs.has ? (semiInExtBrk.E.tpAbs.val - semiInExtBrk.E.tpAbs.span) * semiInExtBrk.E.tpAbs.inExtFrac : 0) - fullyInExtBrksSum.tpPrct.span - (semiInExtBrk.S.tpPrct.has ? semiInExtBrk.S.tpPrct.span * semiInExtBrk.S.tpPrct.inExtFrac : 0) - (semiInExtBrk.E.tpPrct.has ? semiInExtBrk.E.tpPrct.span * semiInExtBrk.E.tpPrct.inExtFrac : 0)) / (1 - fullyInExtBrksSum.tpPrct.val - (semiInExtBrk.S.tpPrct.has ? semiInExtBrk.S.tpPrct.val * semiInExtBrk.S.tpPrct.inExtFrac : 0) - (semiInExtBrk.E.tpPrct.has ? semiInExtBrk.E.tpPrct.val * semiInExtBrk.E.tpPrct.inExtFrac : 0));
each(brkCtx.breaks, function (brk) {
var gapParsed = brk.gapParsed;
if (gapParsed.type === 'tpPrct') {
brk.gapReal = gapPrctSum !== 0
// prctBrksGapRealSum is supposed to be non-negative but add a safe guard
? Math.max(prctBrksGapRealSum, 0) * gapParsed.val / gapPrctSum : 0;
}
if (gapParsed.type === 'tpAbs') {
brk.gapReal = gapParsed.val;
}
if (brk.gapReal == null) {
brk.gapReal = 0;
}
});
}
function pruneTicksByBreak(pruneByBreak, ticks, breaks, getValue, interval, scaleExtent) {
if (pruneByBreak === 'no') {
return;
}
each(breaks, function (brk) {
// break.vmin/vmax that out of extent must not impact the visible of
// normal ticks and labels.
var clampedBrk = clampBreakByExtent(brk, scaleExtent);
if (!clampedBrk) {
return;
}
// Remove some normal ticks to avoid zigzag shapes overlapping with split lines
// and to avoid break labels overlapping with normal tick labels (thouth it can
// also be avoided by `axisLabel.hideOverlap`).
// It's OK to O(n^2) since the number of `ticks` are small.
for (var j = ticks.length - 1; j >= 0; j--) {
var tick = ticks[j];
var val = getValue(tick);
// 1. Ensure there is no ticks inside `break.vmin` and `break.vmax`.
// 2. Use an empirically gap value here. Theoritically `zigzagAmplitude` is
// supposed to be involved to provide better precision but it will brings
// more complexity. The empirically gap value is conservative because break
// labels and normal tick lables are prone to overlapping.
var gap = interval * 3 / 4;
if (val > clampedBrk.vmin - gap && val < clampedBrk.vmax + gap && (pruneByBreak !== 'preserve_extent_bound' || val !== scaleExtent[0] && val !== scaleExtent[1])) {
ticks.splice(j, 1);
}
}
});
}
function addBreaksToTicks(
// The input ticks should be in accending order.
ticks, breaks, scaleExtent,
// Keep the break ends at the same level to avoid an awkward appearance.
getTimeProps) {
each(breaks, function (brk) {
var clampedBrk = clampBreakByExtent(brk, scaleExtent);
if (!clampedBrk) {
return;
}
// - When neight `break.vmin` nor `break.vmax` is in scale extent,
// break label should not be displayed and we do not add them to the result.
// - When only one of `break.vmin` and `break.vmax` is inside the extent and the
// other is outsite, we comply with the extent and display only part of the breaks area,
// because the extent might be determined by user settings (such as `axis.min/max`)
ticks.push({
value: clampedBrk.vmin,
"break": {
type: 'vmin',
parsedBreak: clampedBrk
},
time: getTimeProps ? getTimeProps(clampedBrk) : undefined
});
// When gap is 0, start tick overlap with end tick, but we still count both of them. Break
// area shape can address that overlapping. `axisLabel` need draw both start and end separately,
// otherwise it brings complexity to the logic of label overlapping resolving (e.g., when label
// rotated), and introduces inconsistency to users in `axisLabel.formatter` between gap is 0 or not.
ticks.push({
value: clampedBrk.vmax,
"break": {
type: 'vmax',
parsedBreak: clampedBrk
},
time: getTimeProps ? getTimeProps(clampedBrk) : undefined
});
});
if (breaks.length) {
ticks.sort(function (a, b) {
return a.value - b.value;
});
}
}
/**
* If break and extent does not intersect, return null/undefined.
* If the intersection is only a point at scaleExtent[0] or scaleExtent[1], return null/undefined.
*/
function clampBreakByExtent(brk, scaleExtent) {
var vmin = Math.max(brk.vmin, scaleExtent[0]);
var vmax = Math.min(brk.vmax, scaleExtent[1]);
return vmin < vmax || vmin === vmax && vmin > scaleExtent[0] && vmin < scaleExtent[1] ? {
vmin: vmin,
vmax: vmax,
breakOption: brk.breakOption,
gapParsed: brk.gapParsed,
gapReal: brk.gapReal
} : null;
}
function parseAxisBreakOption(
// raw user input breaks, retrieved from axis model.
breakOptionList, parse, opt) {
var parsedBreaks = [];
if (!breakOptionList) {
return {
breaks: parsedBreaks
};
}
function validatePercent(normalizedPercent, msg) {
if (normalizedPercent >= 0 && normalizedPercent < 1 - 1e-5) {
// Avoid division error.
return true;
}
if (process.env.NODE_ENV !== 'production') {
error(msg + " must be >= 0 and < 1, rather than " + normalizedPercent + " .");
}
return false;
}
each(breakOptionList, function (brkOption) {
if (!brkOption || brkOption.start == null || brkOption.end == null) {
if (process.env.NODE_ENV !== 'production') {
error('The input axis breaks start/end should not be empty.');
}
return;
}
if (brkOption.isExpanded) {
return;
}
var parsedBrk = {
breakOption: clone(brkOption),
vmin: parse(brkOption.start),
vmax: parse(brkOption.end),
gapParsed: {
type: 'tpAbs',
val: 0
},
gapReal: null
};
if (brkOption.gap != null) {
var isPrct = false;
if (isString(brkOption.gap)) {
var trimmedGap = trim(brkOption.gap);
if (trimmedGap.match(/%$/)) {
var normalizedPercent = parseFloat(trimmedGap) / 100;
if (!validatePercent(normalizedPercent, 'Percent gap')) {
normalizedPercent = 0;
}
parsedBrk.gapParsed.type = 'tpPrct';
parsedBrk.gapParsed.val = normalizedPercent;
isPrct = true;
}
}
if (!isPrct) {
var absolute = parse(brkOption.gap);
if (!isFinite(absolute) || absolute < 0) {
if (process.env.NODE_ENV !== 'production') {
error("Axis breaks gap must positive finite rather than (" + brkOption.gap + ").");
}
absolute = 0;
}
parsedBrk.gapParsed.type = 'tpAbs';
parsedBrk.gapParsed.val = absolute;
}
}
if (parsedBrk.vmin === parsedBrk.vmax) {
parsedBrk.gapParsed.type = 'tpAbs';
parsedBrk.gapParsed.val = 0;
}
if (opt && opt.noNegative) {
each(['vmin', 'vmax'], function (se) {
if (parsedBrk[se] < 0) {
if (process.env.NODE_ENV !== 'production') {
error("Axis break." + se + " must not be negative.");
}
parsedBrk[se] = 0;
}
});
}
// Ascending numerical order is the prerequisite of the calculation in Scale#normalize.
// User are allowed to input desending vmin/vmax for simplifying the usage.
if (parsedBrk.vmin > parsedBrk.vmax) {
var tmp = parsedBrk.vmax;
parsedBrk.vmax = parsedBrk.vmin;
parsedBrk.vmin = tmp;
}
parsedBreaks.push(parsedBrk);
});
// Ascending numerical order is the prerequisite of the calculation in Scale#normalize.
parsedBreaks.sort(function (item1, item2) {
return item1.vmin - item2.vmin;
});
// Make sure that the intervals in breaks are not overlap.
var lastEnd = -Infinity;
each(parsedBreaks, function (brk, idx) {
if (lastEnd > brk.vmin) {
if (process.env.NODE_ENV !== 'production') {
error('Axis breaks must not overlap.');
}
parsedBreaks[idx] = null;
}
lastEnd = brk.vmax;
});
return {
breaks: parsedBreaks.filter(function (brk) {
return !!brk;
})
};
}
function identifyAxisBreak(brk, identifier) {
return serializeAxisBreakIdentifier(identifier) === serializeAxisBreakIdentifier(brk);
}
function serializeAxisBreakIdentifier(identifier) {
// We use user input start/end to identify break. Considered cases like `start: new Date(xxx)`,
// Theoretically `Scale#parse` should be used here, but not used currently to reduce dependencies,
// since simply converting to string happens to be correct.
return identifier.start + '_\0_' + identifier.end;
}
/**
* - A break pair represents `[vmin, vmax]`,
* - Only both vmin and vmax item exist, they are counted as a pair.
*/
function retrieveAxisBreakPairs(itemList, getVisualAxisBreak, returnIdx) {
var idxPairList = [];
each(itemList, function (el, idx) {
var vBreak = getVisualAxisBreak(el);
if (vBreak && vBreak.type === 'vmin') {
idxPairList.push([idx]);
}
});
each(itemList, function (el, idx) {
var vBreak = getVisualAxisBreak(el);
if (vBreak && vBreak.type === 'vmax') {
var idxPair = find(idxPairList,
// parsedBreak may be changed, can only use breakOption to match them.
function (pr) {
return identifyAxisBreak(getVisualAxisBreak(itemList[pr[0]]).parsedBreak.breakOption, vBreak.parsedBreak.breakOption);
});
idxPair && idxPair.push(idx);
}
});
var result = [];
each(idxPairList, function (idxPair) {
if (idxPair.length === 2) {
result.push(returnIdx ? idxPair : [itemList[idxPair[0]], itemList[idxPair[1]]]);
}
});
return result;
}
function getTicksLogTransformBreak(tick, logBase, logOriginalBreaks, fixRoundingError) {
var vBreak;
var brkRoundingCriterion;
if (tick["break"]) {
var brk = tick["break"].parsedBreak;
var originalBreak = find(logOriginalBreaks, function (brk) {
return identifyAxisBreak(brk.breakOption, tick["break"].parsedBreak.breakOption);
});
var vmin = fixRoundingError(Math.pow(logBase, brk.vmin), originalBreak.vmin);
var vmax = fixRoundingError(Math.pow(logBase, brk.vmax), originalBreak.vmax);
var gapParsed = {
type: brk.gapParsed.type,
val: brk.gapParsed.type === 'tpAbs' ? fixRound(Math.pow(logBase, brk.vmin + brk.gapParsed.val)) - vmin : brk.gapParsed.val
};
vBreak = {
type: tick["break"].type,
parsedBreak: {
breakOption: brk.breakOption,
vmin: vmin,
vmax: vmax,
gapParsed: gapParsed,
gapReal: brk.gapReal
}
};
brkRoundingCriterion = originalBreak[tick["break"].type];
}
return {
brkRoundingCriterion: brkRoundingCriterion,
vBreak: vBreak
};
}
function logarithmicParseBreaksFromOption(breakOptionList, logBase, parse) {
var opt = {
noNegative: true
};
var parsedOriginal = parseAxisBreakOption(breakOptionList, parse, opt);
var parsedLogged = parseAxisBreakOption(breakOptionList, parse, opt);
var loggedBase = Math.log(logBase);
parsedLogged.breaks = map(parsedLogged.breaks, function (brk) {
var vmin = Math.log(brk.vmin) / loggedBase;
var vmax = Math.log(brk.vmax) / loggedBase;
var gapParsed = {
type: brk.gapParsed.type,
val: brk.gapParsed.type === 'tpAbs' ? Math.log(brk.vmin + brk.gapParsed.val) / loggedBase - vmin : brk.gapParsed.val
};
return {
vmin: vmin,
vmax: vmax,
gapParsed: gapParsed,
gapReal: brk.gapReal,
breakOption: brk.breakOption
};
});
return {
parsedOriginal: parsedOriginal,
parsedLogged: parsedLogged
};
}
var BREAK_MIN_MAX_TO_PARAM = {
vmin: 'start',
vmax: 'end'
};
function makeAxisLabelFormatterParamBreak(extraParam, vBreak) {
if (vBreak) {
extraParam = extraParam || {};
extraParam["break"] = {
type: BREAK_MIN_MAX_TO_PARAM[vBreak.type],
start: vBreak.parsedBreak.vmin,
end: vBreak.parsedBreak.vmax
};
}
return extraParam;
}
export function installScaleBreakHelper() {
registerScaleBreakHelperImpl({
createScaleBreakContext: createScaleBreakContext,
pruneTicksByBreak: pruneTicksByBreak,
addBreaksToTicks: addBreaksToTicks,
parseAxisBreakOption: parseAxisBreakOption,
identifyAxisBreak: identifyAxisBreak,
serializeAxisBreakIdentifier: serializeAxisBreakIdentifier,
retrieveAxisBreakPairs: retrieveAxisBreakPairs,
getTicksLogTransformBreak: getTicksLogTransformBreak,
logarithmicParseBreaksFromOption: logarithmicParseBreaksFromOption,
makeAxisLabelFormatterParamBreak: makeAxisLabelFormatterParamBreak
});
}
+147
View File
@@ -0,0 +1,147 @@
/*
* 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 { getPrecision, round, nice, quantityExponent } from '../util/number.js';
import { bind } from 'zrender/lib/core/util.js';
export function isValueNice(val) {
var exp10 = Math.pow(10, quantityExponent(Math.abs(val)));
var f = Math.abs(val / exp10);
return f === 0 || f === 1 || f === 2 || f === 3 || f === 5;
}
export function isIntervalOrLogScale(scale) {
return scale.type === 'interval' || scale.type === 'log';
}
/**
* @param extent Both extent[0] and extent[1] should be valid number.
* Should be extent[0] < extent[1].
* @param splitNumber splitNumber should be >= 1.
*/
export function intervalScaleNiceTicks(extent, spanWithBreaks, splitNumber, minInterval, maxInterval) {
var result = {};
var interval = result.interval = nice(spanWithBreaks / splitNumber, true);
if (minInterval != null && interval < minInterval) {
interval = result.interval = minInterval;
}
if (maxInterval != null && interval > maxInterval) {
interval = result.interval = maxInterval;
}
// Tow more digital for tick.
var precision = result.intervalPrecision = getIntervalPrecision(interval);
// Niced extent inside original extent
var niceTickExtent = result.niceTickExtent = [round(Math.ceil(extent[0] / interval) * interval, precision), round(Math.floor(extent[1] / interval) * interval, precision)];
fixExtent(niceTickExtent, extent);
return result;
}
export function increaseInterval(interval) {
var exp10 = Math.pow(10, quantityExponent(interval));
// Increase interval
var f = interval / exp10;
if (!f) {
f = 1;
} else if (f === 2) {
f = 3;
} else if (f === 3) {
f = 5;
} else {
// f is 1 or 5
f *= 2;
}
return round(f * exp10);
}
/**
* @return interval precision
*/
export function getIntervalPrecision(interval) {
// Tow more digital for tick.
return getPrecision(interval) + 2;
}
function clamp(niceTickExtent, idx, extent) {
niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);
}
// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.
export function fixExtent(niceTickExtent, extent) {
!isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);
!isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);
clamp(niceTickExtent, 0, extent);
clamp(niceTickExtent, 1, extent);
if (niceTickExtent[0] > niceTickExtent[1]) {
niceTickExtent[0] = niceTickExtent[1];
}
}
export function contain(val, extent) {
return val >= extent[0] && val <= extent[1];
}
var ScaleCalculator = /** @class */function () {
function ScaleCalculator() {
this.normalize = normalize;
this.scale = scale;
}
ScaleCalculator.prototype.updateMethods = function (brkCtx) {
if (brkCtx.hasBreaks()) {
this.normalize = bind(brkCtx.normalize, brkCtx);
this.scale = bind(brkCtx.scale, brkCtx);
} else {
this.normalize = normalize;
this.scale = scale;
}
};
return ScaleCalculator;
}();
export { ScaleCalculator };
function normalize(val, extent) {
if (extent[1] === extent[0]) {
return 0.5;
}
return (val - extent[0]) / (extent[1] - extent[0]);
}
function scale(val, extent) {
return val * (extent[1] - extent[0]) + extent[0];
}
export function logTransform(base, extent, noClampNegative) {
var loggedBase = Math.log(base);
return [
// log(negative) is NaN, so safe guard here.
// PENDING: But even getting a -Infinity still does not make sense in extent.
// Just keep it as is, getting a NaN to make some previous cases works by coincidence.
Math.log(noClampNegative ? extent[0] : Math.max(0, extent[0])) / loggedBase, Math.log(noClampNegative ? extent[1] : Math.max(0, extent[1])) / loggedBase];
}