前端初始化

This commit is contained in:
“hsc”
2026-08-21 15:36:24 +08:00
commit e4d8ecde13
14411 changed files with 2275932 additions and 0 deletions
+250
View File
@@ -0,0 +1,250 @@
/*
* 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 { round, mathRound, mathMin, getPrecision } from '../util/number.js';
import { addCommas } from '../util/format.js';
import Scale from './Scale.js';
import { getIntervalPrecision } from './helper.js';
import { getBreaksUnsafe, getScaleBreakHelper, hasBreaks, simplyParseBreakOption } from './break.js';
import { assert, clone } from 'zrender/lib/core/util.js';
import { getMinorTicks } from './minorTicks.js';
import { getScaleExtentForTickUnsafe, initBreakOrLinearMapper } from './scaleMapper.js';
import { warn } from '../util/log.js';
var IntervalScale = /** @class */function (_super) {
__extends(IntervalScale, _super);
function IntervalScale(setting) {
var _this = _super.call(this) || this;
_this.type = 'interval';
_this.parse = IntervalScale.parse;
setting = setting || {};
var breakParsed = simplyParseBreakOption(_this, setting);
var res = initBreakOrLinearMapper(_this, breakParsed, null);
// @ts-ignore
_this.brk = res.brk;
_this._cfg = {
interval: 0,
intervalPrecision: 2,
intervalCount: undefined,
niceExtent: undefined
};
return _this;
}
IntervalScale.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.getConfig = function () {
return clone(this._cfg);
};
IntervalScale.prototype.setConfig = function (cfg) {
var extent = getScaleExtentForTickUnsafe(this);
if (process.env.NODE_ENV !== 'production') {
assert(cfg.interval != null);
if (cfg.intervalCount != null) {
assert(cfg.intervalCount >= -1 && cfg.intervalPrecision != null
// Do not support intervalCount on axis break currently.
&& !hasBreaks(this));
}
if (cfg.niceExtent != null) {
assert(isFinite(cfg.niceExtent[0]) && isFinite(cfg.niceExtent[1]));
assert(extent[0] <= cfg.niceExtent[0] && cfg.niceExtent[1] <= extent[1]);
assert(round(cfg.niceExtent[0] - cfg.niceExtent[1], getPrecision(cfg.interval)) <= cfg.interval);
}
}
// Reset all.
this._cfg = cfg = clone(cfg);
if (cfg.niceExtent == null) {
// Dropped the auto calculated niceExtent and use user-set extent.
// We assume users want to set both interval and extent to get a better result.
cfg.niceExtent = extent.slice();
}
if (cfg.intervalPrecision == null) {
cfg.intervalPrecision = getIntervalPrecision(cfg.interval);
}
};
/**
* In ascending order.
*/
IntervalScale.prototype.getTicks = function (opt) {
opt = opt || {};
var cfg = this._cfg;
var interval = cfg.interval;
var extent = getScaleExtentForTickUnsafe(this);
var niceExtent = cfg.niceExtent;
var intervalPrecision = cfg.intervalPrecision;
var scaleBreakHelper = getScaleBreakHelper();
var brk = this.brk;
var brkAvailable = scaleBreakHelper && brk;
var ticks = [];
// If interval is 0, return [];
if (!interval) {
return ticks;
}
if (opt.breakTicks === 'only_break' && brkAvailable) {
scaleBreakHelper.addBreaksToTicks(ticks, brk.breaks, extent);
return ticks;
}
if (process.env.NODE_ENV !== 'production') {
assert(niceExtent != null);
}
// [CAVEAT]: If changing this logic, must sync it to `axisAlignTicks.ts`.
// A fail-safe is required since `interval` can be user specified, or for the case
// that using dataZoom toolbox and zoom repeatedly.
var safeLimit = 3000;
if (extent[0] < niceExtent[0]) {
ticks.push({
value: opt.expandToNicedExtent ? round(niceExtent[0] - interval, intervalPrecision) : extent[0]
});
}
var estimateNiceMultiple = function (tickVal, targetTick) {
return mathRound((targetTick - tickVal) / interval);
};
var intervalCount = cfg.intervalCount;
for (var tick = niceExtent[0], niceTickIdx = 0;; niceTickIdx++) {
// Consider case `_extent: [5.2, 5.8], _niceExtent: [6, 5], interval: 1`,
// `_intervalCount` makes sense iff `-1`.
// Consider case `_extent: [5, 5.8], _niceExtent: [5, 5], interval: 1`,
// `_intervalCount` makes sense iff `0`.
if (intervalCount == null) {
if (tick > niceExtent[1] || !isFinite(tick) || !isFinite(niceExtent[1])) {
break;
}
} else {
if (niceTickIdx > intervalCount) {
// nice ticks number should be `intervalCount + 1`
break;
}
// Consider cumulative error, especially caused by rounding, the last nice
// `tick` may be less than or greater than `niceExtent[1]` slightly.
tick = mathMin(tick, niceExtent[1]);
if (niceTickIdx === intervalCount) {
tick = niceExtent[1];
}
}
ticks.push({
value: tick
});
// Avoid rounding error
tick = round(tick + interval, intervalPrecision);
if (brk) {
var moreMultiple = brk.calcNiceTickMultiple(tick, estimateNiceMultiple);
if (moreMultiple >= 0) {
tick = round(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) {
if (process.env.NODE_ENV !== 'production') {
warn('Exceed safe limit in IntervalScale["getTicks"].');
}
return [];
}
}
// Consider this case: the last item of ticks is smaller
// than niceExtent[1] and niceExtent[1] === extent[1].
var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceExtent[1];
if (extent[1] > lastNiceTick) {
ticks.push({
value: opt.expandToNicedExtent ? round(lastNiceTick + interval, intervalPrecision) : extent[1]
});
}
if (brkAvailable) {
scaleBreakHelper.pruneTicksByBreak(opt.pruneByBreak, ticks, brk.breaks, function (item) {
return item.value;
}, cfg.interval, extent);
}
if (brkAvailable && opt.breakTicks !== 'none') {
scaleBreakHelper.addBreaksToTicks(ticks, brk.breaks, extent);
}
return ticks;
};
IntervalScale.prototype.getMinorTicks = function (splitNumber) {
return getMinorTicks(this, splitNumber, getBreaksUnsafe(this), this._cfg.interval);
};
IntervalScale.prototype.getLabel = function (tick, opt) {
if (tick == null) {
return '';
}
var precision = opt && opt.precision;
if (precision == null) {
precision = getPrecision(tick.value) || 0;
} else if (precision === 'auto') {
// Should be more precise then tick.
precision = this._cfg.intervalPrecision;
}
// (1) If `precision` is set, 12.005 should be display as '12.00500'.
// (2) Use `round` (toFixed) to avoid scientific notation like '3.5e-7'.
var dataNum = round(tick.value, precision, true);
return addCommas(dataNum);
};
IntervalScale.type = 'interval';
return IntervalScale;
}(Scale);
Scale.registerClass(IntervalScale);
export default IntervalScale;
+208
View File
@@ -0,0 +1,208 @@
/*
* 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 Scale from './Scale.js';
import IntervalScale from './Interval.js';
import { logScalePowTick, logScaleLogTick } from './helper.js';
import { getBreaksUnsafe, getScaleBreakHelper } from './break.js';
import { getMinorTicks } from './minorTicks.js';
import { decorateScaleMapper, enableScaleMapperFreeze, SCALE_EXTENT_KIND_EFFECTIVE, SCALE_MAPPER_DEPTH_OUT_OF_BREAK } from './scaleMapper.js';
import { map } from 'zrender/lib/core/util.js';
import { isValidBoundsForExtent } from '../util/model.js';
import { isNullableNumberFinite } from '../util/number.js';
var LOOKUP_IDX_EXTENT_START = 0;
var LOOKUP_IDX_EXTENT_END = 1;
var LOOKUP_IDX_BREAK_START = 2;
/**
* @final NEVER inherit me!
*/
var LogScale = /** @class */function (_super) {
__extends(LogScale, _super);
function LogScale(setting) {
var _this = _super.call(this) || this;
_this.type = 'log';
_this.parse = IntervalScale.parse;
_this.base = setting.logBase || 10;
var lookupFrom = [];
var lookupTo = [];
var lookup = _this._lookup = {
from: lookupFrom,
to: lookupTo
};
lookupFrom[LOOKUP_IDX_EXTENT_START] = lookupFrom[LOOKUP_IDX_EXTENT_END] = lookupTo[LOOKUP_IDX_EXTENT_START] = lookupTo[LOOKUP_IDX_EXTENT_END] = NaN;
decorateScaleMapper(_this, LogScale.mapperMethods);
var scaleBreakHelper = getScaleBreakHelper();
var breakOption = setting.breakOption;
var out = {
lookup: lookup
};
if (scaleBreakHelper) {
scaleBreakHelper.parseAxisBreakOptionInwardTransform(breakOption, _this, {
noNegative: true
}, LOOKUP_IDX_BREAK_START, out);
}
_this.powStub = new IntervalScale({
breakParsed: out.original
});
_this.intervalStub = new IntervalScale({
breakParsed: out.transformed
});
enableScaleMapperFreeze(_this, _this.intervalStub);
return _this;
}
LogScale.prototype.getTicks = function (opt) {
var base = this.base;
var powStub = this.powStub;
var scaleBreakHelper = getScaleBreakHelper();
var intervalStub = this.intervalStub;
var intervalExtent = intervalStub.getExtent();
var powExtent = powStub.getExtent();
var powOpt = {
lookup: {
from: intervalExtent,
to: powExtent
}
};
return map(intervalStub.getTicks(opt || {}), function (tick) {
var val = tick.value;
var powVal = logScalePowTick(val, base, powOpt);
var vBreak;
if (scaleBreakHelper) {
var brkPowResult = scaleBreakHelper.getTicksBreakOutwardTransform(this, tick, getBreaksUnsafe(powStub), this._lookup);
if (brkPowResult) {
vBreak = brkPowResult.vBreak;
powVal = brkPowResult.tickVal;
}
}
return {
value: powVal,
"break": vBreak
};
}, this);
};
LogScale.prototype.getMinorTicks = function (splitNumber) {
return getMinorTicks(this, splitNumber, getBreaksUnsafe(this.powStub),
// NOTE: minor ticks are in the log scale value to visually hint users "logarithm".
this.intervalStub.getConfig().interval);
};
LogScale.prototype.getLabel = function (data, opt) {
return this.intervalStub.getLabel(data, opt);
};
LogScale.type = 'log';
LogScale.mapperMethods = {
needTransform: function () {
return true;
},
normalize: function (val) {
return this.intervalStub.normalize(logScaleLogTick(val, this.base));
},
scale: function (val) {
// PENDING: Input `intervalStub.getExtent()` and `powStub.getExtent()` may
// break monotonicity. Do not do it until real problems found.
return logScalePowTick(this.intervalStub.scale(val), this.base, null);
},
transformIn: function (val, opt) {
val = logScaleLogTick(val, this.base);
return opt && opt.depth === SCALE_MAPPER_DEPTH_OUT_OF_BREAK ? val : this.intervalStub.transformIn(val, opt);
},
transformOut: function (val, opt) {
var depth = opt ? opt.depth : null;
tmpTransformOutOpt1.depth = depth;
tmpTransformOutOpt2.lookup = this._lookup;
return logScalePowTick(depth === SCALE_MAPPER_DEPTH_OUT_OF_BREAK ? val : this.intervalStub.transformOut(val, tmpTransformOutOpt1), this.base, tmpTransformOutOpt2);
},
contain: function (val) {
return this.powStub.contain(val);
},
/**
* NOTICE: The caller should ensure `start` and `end` are both non-negative.
*/
setExtent: function (start, end) {
this.setExtent2(SCALE_EXTENT_KIND_EFFECTIVE, start, end);
},
setExtent2: function (kind, start, end) {
if (!isValidBoundsForExtent(start, end) || start <= 0 || end <= 0) {
return;
}
var lookupTo = tmpNotUsedArr;
var lookupFrom = tmpNotUsedArr;
if (kind === SCALE_EXTENT_KIND_EFFECTIVE) {
var lookup = this._lookup;
lookupTo = lookup.to;
lookupFrom = lookup.from;
}
this.powStub.setExtent2(kind, lookupTo[LOOKUP_IDX_EXTENT_START] = start, lookupTo[LOOKUP_IDX_EXTENT_END] = end);
var base = this.base;
this.intervalStub.setExtent2(kind, lookupFrom[LOOKUP_IDX_EXTENT_START] = logScaleLogTick(start, base), lookupFrom[LOOKUP_IDX_EXTENT_END] = logScaleLogTick(end, base));
},
getFilter: function () {
return {
g: 0
};
},
sanitize: function (value, dataExtent) {
// Conservative - if dataExtent is invalid, do not sanitize.
if (isValidBoundsForExtent(dataExtent[0], dataExtent[1]) && isNullableNumberFinite(value) && value <= 0) {
// `DataStore` has ensured that `dataExtent` is valid for LogScale.
value = dataExtent[0];
}
return value;
},
getDefaultStartValue: function () {
return 1;
},
getExtent: function () {
return this.powStub.getExtent();
},
getExtentUnsafe: function (kind, depth) {
return depth === null ? this.powStub.getExtentUnsafe(kind, null) : this.intervalStub.getExtentUnsafe(kind, depth);
}
};
return LogScale;
}(Scale);
Scale.registerClass(LogScale);
var tmpTransformOutOpt1 = {};
var tmpTransformOutOpt2 = {};
var tmpNotUsedArr = [];
export default LogScale;
+233
View File
@@ -0,0 +1,233 @@
/*
* 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
*/
import Scale from './Scale.js';
import OrdinalMeta from '../data/OrdinalMeta.js';
import { isArray, map, isObject, isString } from 'zrender/lib/core/util.js';
import { mathMin, mathRound } from '../util/number.js';
import { decorateScaleMapper, enableScaleMapperFreeze, getScaleExtentForTickUnsafe, initBreakOrLinearMapper } from './scaleMapper.js';
import { ordinalScaleCreateTicks } from './helper.js';
var OrdinalScale = /** @class */function (_super) {
__extends(OrdinalScale, _super);
function OrdinalScale(setting) {
var _this = _super.call(this) || this;
_this.type = 'ordinal';
_this.parse = OrdinalScale.parse;
decorateScaleMapper(_this, OrdinalScale.decoratedMethods);
var ordinalMeta = setting.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;
// Create an interval LinearScaleMapper, and decorate it.
var res = initBreakOrLinearMapper(null, null,
// Do not support break in OrdinalScale yet.
setting.extent || [0, ordinalMeta.categories.length - 1]);
_this._mapper = res.mapper;
enableScaleMapperFreeze(_this, res.mapper);
return _this;
}
OrdinalScale.parse = function (val) {
// Caution: Math.round(null) will return `0` rather than `NaN`
if (val == null) {
val = NaN;
} else if (isString(val)) {
val = this._ordinalMeta.getOrdinal(val);
if (val == null) {
val = NaN;
}
} else {
// The val from user input might be float.
val = mathRound(val);
}
return val;
};
/**
* PENDING: currently this method is not used.
* `makeCategoryTicks` is effectively used.
*/
OrdinalScale.prototype.getTicks = function () {
var ticks = [];
ordinalScaleCreateTicks(this, 0, function (tick) {
ticks.push(tick);
});
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 = mathMin(allCategoryLen, infoOrdinalNumbers.length); tickNum < len; ++tickNum) {
var ordinalNumber = ordinalsByTick[tickNum] = infoOrdinalNumbers[tickNum];
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[tickNum] = 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(tick.value);
* // case0
* const rawOrdinalValue = axisModel.getCategories()[ordinalNumber];
* // case1
* const rawOrdinalValue = this._ordinalMeta.categories[ordinalNumber];
* // case2
* const coord = axis.dataToCoord(ordinalNumber);
* ```
*
* value 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.
*/
OrdinalScale.prototype.getRawOrdinalNumber = function (tickValue) {
var ordinalNumbersByTick = this._ordinalNumbersByTick;
return ordinalNumbersByTick && tickValue >= 0 && tickValue < ordinalNumbersByTick.length ? ordinalNumbersByTick[tickValue] : tickValue;
};
/**
* Get item on tick
*/
OrdinalScale.prototype.getLabel = function (tick) {
if (!this.isBlank()) {
var ordinalNumber = this.getRawOrdinalNumber(tick.value);
var category = this._ordinalMeta.categories[ordinalNumber];
// Note that if no data, ordinalMeta.categories is an empty array.
// Return empty if it's not exist.
return category == null ? '' : category + '';
}
};
/**
* NOTICE: This is different from `.getOrdinalMeta().length` when extent
* is specified by `xxxAxis.min/max` or by `dataZoom`.
*/
OrdinalScale.prototype.count = function () {
var extent = getScaleExtentForTickUnsafe(this._mapper);
return extent[1] - extent[0] + 1;
};
OrdinalScale.prototype.getOrdinalMeta = function () {
return this._ordinalMeta;
};
OrdinalScale.type = 'ordinal';
OrdinalScale.decoratedMethods = {
needTransform: function () {
return this._mapper.needTransform();
},
contain: function (val) {
return this._mapper.contain(this._getTickNumber(val)) && val >= 0 && val < this._ordinalMeta.categories.length;
},
normalize: function (val) {
return this._mapper.normalize(this._getTickNumber(val));
},
scale: function (val) {
return this.getRawOrdinalNumber(mathRound(this._mapper.scale(val)));
},
transformIn: function (val, opt) {
return this._mapper.transformIn(this._getTickNumber(val), opt);
},
transformOut: function (val, opt) {
return this.getRawOrdinalNumber(this._mapper.transformOut(val, opt));
},
getExtent: function () {
return this._mapper.getExtent();
},
getExtentUnsafe: function (kind, depth) {
return this._mapper.getExtentUnsafe(kind, depth);
},
/**
* NOTICE: OrdinalScale extent should always originates from
* `[0, ordinalMeta.categories.length - 1]`, regardless of min/max of `series.data`.
* But settings like `xxxAxis.min/max` can still modify the extent.
* It is handled by constructor of `ScaleRawExtentInfo`.
*/
setExtent: function (start, end) {
return this._mapper.setExtent(start, end);
},
setExtent2: function (kind, start, end) {
return this._mapper.setExtent2(kind, start, end);
}
};
return OrdinalScale;
}(Scale);
Scale.registerClass(OrdinalScale);
export default OrdinalScale;
+68
View File
@@ -0,0 +1,68 @@
/*
* 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';
var Scale = /** @class */function () {
function Scale() {}
/**
* When axis extent depends on data and no data exists,
* axis ticks should not be drawn, which is named 'blank'.
*
* @final NEVER override!
*/
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'.
*
* @final NEVER override!
*/
Scale.prototype.setBlank = function (isBlank) {
this._isBlank = isBlank;
};
return Scale;
}();
clazzUtil.enableClassManagement(Scale);
export default Scale;
+582
View File
@@ -0,0 +1,582 @@
/*
* 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 { ensureValidSplitNumber } from './helper.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 { getBreaksUnsafe, getScaleBreakHelper, simplyParseBreakOption } from './break.js';
import { getMinorTicks } from './minorTicks.js';
import { getScaleLinearSpanEffective, getScaleExtentForTickUnsafe, initBreakOrLinearMapper } from './scaleMapper.js';
import { removeDuplicates, removeDuplicatesGetKeyFromValueProp } from '../util/model.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(setting) {
var _this = _super.call(this) || this;
_this.type = 'time';
_this.parse = TimeScale.parse;
_this._locale = setting.locale;
_this._useUTC = setting.useUTC;
_this._interval = 0;
var breakParsed = simplyParseBreakOption(_this, setting);
var res = initBreakOrLinearMapper(_this, breakParsed, null);
// @ts-ignore
_this.brk = res.brk;
return _this;
}
/**
* Get label is mainly for other components like dataZoom, tooltip.
*/
TimeScale.prototype.getLabel = function (tick) {
return format(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, this._useUTC, this._locale);
};
TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) {
return leveledFormat(tick, idx, labelFormatter, this._locale, this._useUTC);
};
TimeScale.prototype.getTicks = function (opt) {
opt = opt || {};
var interval = this._interval;
var extent = getScaleExtentForTickUnsafe(this);
var scaleBreakHelper = getScaleBreakHelper();
var brk = this.brk;
var brkAvailable = scaleBreakHelper && brk;
var ticks = [];
// If interval is 0, return [];
if (!interval) {
return ticks;
}
var useUTC = this._useUTC;
if (brkAvailable && opt.breakTicks === 'only_break') {
getScaleBreakHelper().addBreaksToTicks(ticks, brk.breaks, extent);
return ticks;
}
ticks = createIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent, getScaleLinearSpanEffective(this), brk);
var upperUnitIndex = primaryTimeUnits.length - 1;
var maxLevel = 0;
each(ticks, function (tick) {
if (tick.time) {
upperUnitIndex = Math.min(upperUnitIndex, indexOf(primaryTimeUnits, tick.time.upperTimeUnit));
maxLevel = Math.max(maxLevel, tick.time.level);
}
});
if (brkAvailable) {
getScaleBreakHelper().pruneTicksByBreak(opt.pruneByBreak, ticks, brk.breaks, function (item) {
return item.value;
}, this._approxInterval, extent);
}
if (brkAvailable && opt.breakTicks !== 'none') {
getScaleBreakHelper().addBreaksToTicks(ticks, brk.breaks, extent, function (trimmedBrk) {
// @see `parseTimeAxisLabelFormatterDictionary`.
var lowerBrkUnitIndex = Math.max(indexOf(primaryTimeUnits, getUnitFromValue(trimmedBrk.vmin, useUTC)), indexOf(primaryTimeUnits, getUnitFromValue(trimmedBrk.vmax, useUTC)));
var upperBrkUnitIndex = 0;
for (var unitIdx = 0; unitIdx < primaryTimeUnits.length; unitIdx++) {
if (!isPrimaryUnitValueAndGreaterSame(primaryTimeUnits[unitIdx], trimmedBrk.vmin, trimmedBrk.vmax, useUTC)) {
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.getMinorTicks = function (splitNumber) {
return getMinorTicks(this, splitNumber, getBreaksUnsafe(this), this._interval);
};
TimeScale.prototype.setTimeInterval = function (opt) {
this._interval = opt.interval;
this._approxInterval = opt.approxInterval;
this._minLevelUnit = opt.minLevelUnit;
};
TimeScale.parse = function (val) {
// `val` might be a float (e.g., calculated from percent), so call `round`.
return isNumber(val) ? Math.round(val) : +numberUtil.parseDate(val);
};
TimeScale.type = 'time';
return TimeScale;
}(Scale);
/**
* 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) {
// If less than 1, the getTicks loop will inevitably deed loop and read safeLimit.
return numberUtil.mathMax(numberUtil.nice(approxInterval, true), 1);
}
// 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 createIntervalTicks(bottomUnitName, approxInterval, isUTC, extent, innermostSpan, brk) {
// A fail-safe is required since `interval` can be user specified, or for the case
// that using dataZoom toolbox and zoom repeatedly.
var safeLimit = 3000;
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 TimeScale["getTicks"].');
}
break;
}
date[setMethodName](date[getMethodName]() + interval);
dateTime = date.getTime();
if (brk) {
var moreMultiple = brk.calcNiceTickMultiple(dateTime, estimateNiceMultiple);
if (moreMultiple > 0) {
date[setMethodName](date[getMethodName]() + moreMultiple * interval);
dateTime = date.getTime();
}
}
}
// This extra tick is for calculating ticks of next level. Will not been added to the final result
out.push({
value: dateTime,
// extent[1] should be added; deduplication will be performed later.
notAdd: dateTime > extent[1]
});
}
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 = innermostSpan / 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 maxLevel = levelsTicksInExtent.length - 1;
var ticks = [];
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
}
});
}
}
// Remove duplicates, which may cause jitter of `splitArea` and other bad cases.
removeDuplicates(ticks, removeDuplicatesGetKeyFromValueProp, null);
ticks.sort(function (a, b) {
return a.value - b.value;
});
var currMinTick = ticks[0];
var currMaxTick = ticks[ticks.length - 1];
var extent0Unit = getUnitFromValue(extent[0], isUTC);
var extent1Unit = getUnitFromValue(extent[1], isUTC);
if (!currMinTick || currMinTick.value > extent[0]) {
ticks.unshift({
value: extent[0],
time: {
level: 0,
upperTimeUnit: extent0Unit,
lowerTimeUnit: extent0Unit
},
notNice: true
});
}
if (!currMaxTick || currMaxTick.value < extent[1]) {
ticks.push({
value: extent[1],
time: {
level: 0,
upperTimeUnit: extent1Unit,
lowerTimeUnit: extent1Unit
},
notNice: true
});
}
return ticks;
}
export var calcNiceForTimeScale = function (scale, opt) {
var extent = scale.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;
}
scale.setExtent(extent[0], extent[1]);
var splitNumber = ensureValidSplitNumber(opt.splitNumber, 10);
var approxInterval = getScaleLinearSpanEffective(scale) / splitNumber;
var minInterval = opt.minInterval;
var maxInterval = opt.maxInterval;
if (minInterval != null && approxInterval < minInterval) {
approxInterval = minInterval;
}
if (maxInterval != null && approxInterval > maxInterval) {
approxInterval = maxInterval;
}
var scaleIntervalsLen = scaleIntervals.length;
var idx = Math.min(bisect(scaleIntervals, approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1);
// Interval that can be used to calculate ticks
var interval = scaleIntervals[idx][1];
// Min level used when picking ticks from top down.
// We check one more level to avoid the ticks are to sparse in some case.
var minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0];
scale.setTimeInterval({
approxInterval: approxInterval,
interval: interval,
minLevelUnit: minLevelUnit
});
};
Scale.registerClass(TimeScale);
export default TimeScale;
+70
View File
@@ -0,0 +1,70 @@
/*
* 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;
}
export function simplyParseBreakOption(scale, opt) {
var scaleBreakHelper = getScaleBreakHelper();
var breakOption = opt.breakOption;
var breakParsed = opt.breakParsed;
if (!breakParsed && scaleBreakHelper) {
breakParsed = scaleBreakHelper.parseAxisBreakOption(breakOption, scale);
}
return breakParsed;
}
export function getBreaksUnsafe(scale) {
var brk = scale.brk;
return brk ? brk.breaks : [];
}
export function hasBreaks(scale) {
var brk = scale.brk;
return brk ? brk.hasBreaks() : false;
}
+651
View File
@@ -0,0 +1,651 @@
/*
* 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, filter, find, isString, map, trim } from 'zrender/lib/core/util.js';
import { error } from '../util/log.js';
import { registerScaleBreakHelperImpl } from './break.js';
import { mathMax, mathMin, mathRound } from '../util/number.js';
import { decorateScaleMapper, enableScaleMapperFreeze, initLinearScaleMapper, SCALE_EXTENT_KIND_EFFECTIVE, SCALE_MAPPER_DEPTH_OUT_OF_BREAK } from './scaleMapper.js';
import { isValidBoundsForExtent } from '../util/model.js';
var BreakScaleMapperImpl = /** @class */function () {
function BreakScaleMapperImpl(breakParsed, initialExtent) {
decorateScaleMapper(this, BreakScaleMapperImpl.decoratedMethods);
this._outOfBrk = initLinearScaleMapper(null, initialExtent);
var mapper = this._linear = initLinearScaleMapper(null, initialExtent);
enableScaleMapperFreeze(this, mapper);
this.breaks = breakParsed && breakParsed.breaks || [];
}
BreakScaleMapperImpl.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.
*/
BreakScaleMapperImpl.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 && mathRound(multiple) === multiple);
}
return multiple;
}
}
return 0;
};
BreakScaleMapperImpl.decoratedMethods = {
needTransform: function () {
return !this.breaks.length;
},
getExtent: function () {
return this._outOfBrk.getExtent();
},
getExtentUnsafe: function (kind, depth) {
return depth == null || depth === SCALE_MAPPER_DEPTH_OUT_OF_BREAK ? this._outOfBrk.getExtentUnsafe(kind, null) : this._linear.getExtentUnsafe(kind, null);
},
setExtent: function (start, end) {
this.setExtent2(SCALE_EXTENT_KIND_EFFECTIVE, start, end);
},
setExtent2: function (kind, start, end) {
if (isValidBoundsForExtent(start, end)) {
if (kind === SCALE_EXTENT_KIND_EFFECTIVE) {
updateAxisBreakGapReal(this, [start, end]);
}
this._outOfBrk.setExtent2(kind, start, end);
this._linear.setExtent2(kind, this.transformIn(start, null), this.transformIn(end, null));
}
},
normalize: function (val) {
return this._linear.normalize(this.transformIn(val, null));
},
scale: function (val) {
return this.transformOut(this._linear.scale(val), null);
},
contain: function (val) {
return this._outOfBrk.contain(val);
},
/**
* a.k.a., "elapse"
* 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:
* `transformIn` and `transformOut` has nothing to do with "scale extent" - out of extent is supported.
*/
transformIn: function (val, opt) {
if (opt && opt.depth === SCALE_MAPPER_DEPTH_OUT_OF_BREAK) {
return 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;
},
/**
* @see transformIn
* a.k.a., "unelapse"
*/
transformOut: function (elapsedVal, opt) {
if (opt && opt.depth === SCALE_MAPPER_DEPTH_OUT_OF_BREAK) {
return 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 BreakScaleMapperImpl;
}();
;
function createBreakScaleMapper(breakParsed, initialExtent) {
return new BreakScaleMapperImpl(breakParsed, initialExtent);
}
// Both can start with any finite value, and are not necessarily 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 brkMapper.breaks will be calculated.
*/
function updateAxisBreakGapReal(brkMapper, 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(brkMapper.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(brkMapper.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
? mathMax(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 = mathMax(brk.vmin, scaleExtent[0]);
var vmax = mathMin(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, scale, 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: scale.parse(brkOption.start),
vmax: scale.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 = scale.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: filter(parsedBreaks, 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 getTicksBreakOutwardTransform(scale, tick, outermostBreaks, lookup) {
if (!tick["break"]) {
return;
}
var brk = tick["break"].parsedBreak;
var originalBrkItem = find(outermostBreaks, function (brk) {
return identifyAxisBreak(brk.breakOption, tick["break"].parsedBreak.breakOption);
});
// NOTE: `tick.break` may have been clamped by scale extent.
var opt = {
lookup: lookup,
depth: SCALE_MAPPER_DEPTH_OUT_OF_BREAK
};
var vmin = scale.transformOut(brk.vmin, opt);
var vmax = scale.transformOut(brk.vmax, opt);
var parsedBreak = {
vmin: vmin,
vmax: vmax,
breakOption: brk.breakOption,
gapParsed: clone(originalBrkItem.gapParsed),
gapReal: brk.gapReal
};
return {
tickVal: parsedBreak[tick["break"].type],
vBreak: {
type: tick["break"].type,
parsedBreak: parsedBreak
}
};
}
function parseAxisBreakOptionInwardTransform(breakOptionList, scale, parseOpt, lookupStartIdx, out) {
out.original = parseAxisBreakOption(breakOptionList, scale, parseOpt);
var transformed = out.transformed = parseAxisBreakOption(breakOptionList, scale, parseOpt);
var lookup = out.lookup;
transformed.breaks = map(transformed.breaks, function (brk, idx) {
var transOpt = {
depth: SCALE_MAPPER_DEPTH_OUT_OF_BREAK
};
var vmin = scale.transformIn(brk.vmin, transOpt);
var vmax = scale.transformIn(brk.vmax, transOpt);
var gapParsed = {
type: brk.gapParsed.type,
val: brk.gapParsed.type === 'tpAbs' ? scale.transformIn(brk.vmin + brk.gapParsed.val, transOpt) - vmin : brk.gapParsed.val
};
lookup.from[lookupStartIdx + idx] = vmin;
lookup.to[lookupStartIdx + idx] = brk.vmin;
lookup.from[lookupStartIdx + idx + 1] = vmax;
lookup.to[lookupStartIdx + idx + 1] = brk.vmax;
return {
vmin: vmin,
vmax: vmax,
gapParsed: gapParsed,
gapReal: brk.gapReal,
breakOption: brk.breakOption
};
});
}
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({
createBreakScaleMapper: createBreakScaleMapper,
pruneTicksByBreak: pruneTicksByBreak,
addBreaksToTicks: addBreaksToTicks,
parseAxisBreakOption: parseAxisBreakOption,
identifyAxisBreak: identifyAxisBreak,
serializeAxisBreakIdentifier: serializeAxisBreakIdentifier,
retrieveAxisBreakPairs: retrieveAxisBreakPairs,
getTicksBreakOutwardTransform: getTicksBreakOutwardTransform,
parseAxisBreakOptionInwardTransform: parseAxisBreakOptionInwardTransform,
makeAxisLabelFormatterParamBreak: makeAxisLabelFormatterParamBreak
});
}
+260
View File
@@ -0,0 +1,260 @@
/*
* 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, mathPow, mathMax, mathRound, mathLog, mathAbs, mathFloor, mathCeil } from '../util/number.js';
import { isValidNumberForExtent } from '../util/model.js';
import { getScaleExtentForTickUnsafe } from './scaleMapper.js';
/**
* See also method `nice` in `src/util/number.ts`.
*/
// export function isValueNice(val: number) {
// const exp10 = Math.pow(10, quantityExponent(Math.abs(val)));
// const f = Math.abs(round(val / exp10, 0));
// return f === 0
// || f === 1
// || f === 2
// || f === 3
// || f === 5;
// }
export function isIntervalOrLogScale(scale) {
return isIntervalScale(scale) || isLogScale(scale);
}
export function isIntervalOrTimeScale(scale) {
return isIntervalScale(scale) || isTimeScale(scale);
}
export function isIntervalScale(scale) {
return scale.type === 'interval';
}
export function isTimeScale(scale) {
return scale.type === 'time';
}
export function isLogScale(scale) {
return scale.type === 'log';
}
export function isOrdinalScale(scale) {
return scale.type === 'ordinal';
}
/**
* @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;
}
var precision = result.intervalPrecision = getIntervalPrecision(interval);
// Niced extent inside original extent
result.niceTickExtent = [round(mathCeil(extent[0] / interval) * interval, precision), round(mathFloor(extent[1] / interval) * interval, precision)];
return result;
}
/**
* The input `niceInterval` should be generated
* from `nice` method in `src/util/number.ts`, or
* from `increaseInterval` itself.
*/
export function increaseInterval(niceInterval) {
var exponent = quantityExponent(niceInterval);
// No rounding error in Math.pow(10, integer).
var exp10 = mathPow(10, exponent);
// Fix IEEE 754 float rounding error
var f = mathRound(niceInterval / 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;
}
// Fix IEEE 754 float rounding error
return round(f * exp10, -exponent);
}
export function getIntervalPrecision(niceInterval) {
// Tow more digital for tick.
// NOTE: `2` was introduced in commit `af2a2a9f6303081d7c3b52f0a38add07b4c6e0c7`;
// it works on "nice" interval, but seems not necessarily mathematically required.
return getPrecision(niceInterval) + 2;
}
/**
* NOTE:
* - If `val` is `NaN`, return `NaN`.
* - If `val` is `0`, return `-Infinity`.
* - If `val` is negative, return `NaN`.
*
* @see {DataStore#getDataExtent} It handles non-positive values for logarithm scale.
*/
export function logScaleLogTick(val, base) {
// NOTE:
// - rounding error may happen above, typically expecting `log10(1000)` but actually
// getting `2.9999999999999996`, but generally it does not matter since they are not
// used to display.
// - Consider backward compatibility and other log bases, do not use `Math.log10`.
return mathLog(val) / mathLog(base);
}
/**
* Cumulative rounding errors cause the logarithm operation to become non-invertible by simply exponentiation.
* - `Math.pow(10, integer)` itself has no rounding error. But,
* - If `linearTickVal` is generated internally by `calcNiceTicks`, it may be still "not nice" (not an integer)
* when it is `extent[i]`.
* - If `linearTickVal` is generated outside (e.g., by `scaleCalcAlign`) and set by `setExtent`,
* `logScaleLogTick` may already have introduced rounding errors even for "nice" values.
* But invertible is required when the original `extent[i]` need to be respected, or "nice" ticks need to be
* displayed instead of something like `5.999999999999999`, which is addressed in this function.
* See also `#4158`.
*
* [CAUTION]:
* Monotonicity may be broken on extent ends - callers must make sure it does not matter.
*/
export function logScalePowTick(
// `tickVal` should be in the linear space.
linearTickVal, base, opt) {
var lookup = opt && opt.lookup;
if (lookup) {
for (var i = 0; i < lookup.from.length; i++) {
if (linearTickVal === lookup.from[i]) {
return lookup.to[i];
}
}
}
return mathPow(base, linearTickVal);
}
/**
* For `IntervalScale`, convert `rawExtent` to:
* - Be no non-finite number.
* - Be `extent[0] < extent[1]`- no equal; otherwise, additional handling is required
* in "nice" and "align" ticks.
*/
export function intervalScaleEnsureValidExtent(rawExtent, fixMinMax, rawExtentResult) {
var extent = rawExtent.slice();
// PENDING:
// This implementation is not rigorous, but has long been in use.
// If extent start and end are same, expand them
if (extent[0] === extent[1]) {
// If `containShape`, the extent must be evenly distributed to both sides;
// otherwise, shape (e.g., bars) may be overflow and clipped.
var containShapeRequired = rawExtentResult && rawExtentResult.ctnShp;
if (extent[0] !== 0) {
// Expand extent
// Note that extents can be both negative. See #13154
var expandSize = mathAbs(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 (!fixMinMax[1]) {
extent[1] += expandSize / 2;
extent[0] -= expandSize / 2;
} else {
extent[0] -= expandSize / 2;
}
} else {
if (containShapeRequired) {
extent[0] = -1;
extent[1] = 1;
} else {
extent[1] = 1;
}
}
}
// For example, if there are no series data, extent may be `[Infinity, -Infinity]` here.
if (!isValidNumberForExtent(extent[0]) || !isValidNumberForExtent(extent[1])) {
extent[0] = 0;
extent[1] = 1;
}
if (extent[1] < extent[0]) {
extent.reverse();
}
return extent;
}
export function extentDiffers(extent1, extent2) {
return [extent1[0] !== extent2[0], extent1[1] !== extent2[1]];
}
export function ensureValidSplitNumber(rawSplitNumber, defaultSplitNumber) {
rawSplitNumber = rawSplitNumber || defaultSplitNumber;
return mathRound(mathMax(rawSplitNumber, 1));
}
/**
* NOTE: The result can have only one item, e.g., when `extent[0] === extent[1]`
* and `categoryInterval === 0`.
*/
export function ordinalScaleCreateTicks(ordinalScale,
// `categoryInterval` is the number part of `CategoryTickLabelSplitIntervalOption`.
categoryInterval, addItem) {
var extent = getScaleExtentForTickUnsafe(ordinalScale);
var startTick = extent[0];
var tickCount = ordinalScale.count();
var step = Math.max((categoryInterval || 0) + 1, 1);
// Calculate start tick based on zero if possible to keep label consistent
// while zooming and moving while interval > 0. Otherwise the selection
// of displayable ticks and symbols probably keep changing.
if (startTick !== 0 && step > 1 && tickCount / step > 2) {
startTick = Math.round(Math.ceil(startTick / step) * step);
}
// min max labels may be excluded if `startTick > 0`, but they should be always
// included and the label display strategy is adopted uniformly later in `AxisBuilder`.
if (startTick !== extent[0]) {
addItemInternally(extent[0], true, true);
}
var tickValue = startTick;
for (; tickValue <= extent[1]; tickValue += step) {
addItemInternally(tickValue, false, tickValue === extent[0] || tickValue === extent[1]);
}
if (tickValue - step !== extent[1]) {
addItemInternally(extent[1], true, true);
}
function addItemInternally(tickValue, offInterval, isExtentBoundary) {
addItem({
value: tickValue,
offInterval: offInterval
}, isExtentBoundary);
}
}
+84
View File
@@ -0,0 +1,84 @@
/*
* 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 { round } from '../util/number.js';
import { getScaleBreakHelper } from './break.js';
import { getIntervalPrecision } from './helper.js';
export function getMinorTicks(scale, splitNumber, breaks, scaleInterval) {
var ticks = scale.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 = scale.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 = getIntervalPrecision(minorInterval);
while (count < splitNumber - 1) {
var minorTick = round(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, breaks, function (value) {
return value;
}, scaleInterval, extent);
minorTicks.push(minorTicksGroup);
}
return minorTicks;
}
+207
View File
@@ -0,0 +1,207 @@
/*
* 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, bind, each, extend, keys, noop } from 'zrender/lib/core/util.js';
import { initExtentForUnion, isValidBoundsForExtent } from '../util/model.js';
import { getScaleBreakHelper } from './break.js';
import { error } from '../util/log.js';
export var SCALE_EXTENT_KIND_EFFECTIVE = 0;
export var SCALE_EXTENT_KIND_MAPPING = 1;
var SCALE_MAPPER_METHOD_NAMES_MAP = {
needTransform: 1,
normalize: 1,
scale: 1,
transformIn: 1,
transformOut: 1,
contain: 1,
getExtent: 1,
getExtentUnsafe: 1,
setExtent: 1,
setExtent2: 1,
getFilter: 1,
sanitize: 1,
getDefaultStartValue: 1,
freeze: 1
};
var SCALE_MAPPER_METHOD_NAMES = keys(SCALE_MAPPER_METHOD_NAMES_MAP);
export var SCALE_MAPPER_DEPTH_OUT_OF_BREAK = 2;
export var SCALE_MAPPER_DEPTH_INNERMOST = 3;
export function initBreakOrLinearMapper(
// If input `null/undefined`, a mapper will be created.
mapper, breakParsed, initialExtent) {
var brk;
mapper = mapper || {};
var scaleBreakHelper = getScaleBreakHelper();
if (scaleBreakHelper) {
var brkMapper_1 = scaleBreakHelper.createBreakScaleMapper(breakParsed, initialExtent);
if (brkMapper_1.hasBreaks()) {
// Some `ScaleMapper` methods (such as `normalize`) needs to be fast for large data
// when no breaks, so mount break methods only when breaks really exist.
each(SCALE_MAPPER_METHOD_NAMES, function (methodName) {
if (brkMapper_1[methodName]) {
mapper[methodName] = bind(brkMapper_1[methodName], brkMapper_1);
}
});
brk = brkMapper_1;
}
}
if (brk == null) {
initLinearScaleMapper(mapper, initialExtent);
}
return {
brk: brk,
mapper: mapper
};
}
export function decorateScaleMapper(host, decoratedMapperMethods) {
each(SCALE_MAPPER_METHOD_NAMES, function (methodName) {
host[methodName] = decoratedMapperMethods[methodName];
});
}
export function enableScaleMapperFreeze(host, subMapper) {
host.freeze = noop;
if (process.env.NODE_ENV !== 'production') {
host.freeze = function () {
subMapper.freeze();
};
}
;
}
export function getScaleExtentForTickUnsafe(mapper) {
return mapper.getExtentUnsafe(SCALE_EXTENT_KIND_EFFECTIVE, SCALE_MAPPER_DEPTH_OUT_OF_BREAK);
}
export function getScaleExtentForMappingUnsafe(mapper,
// NullUndefined means the outermost space.
depth) {
return mapper.getExtentUnsafe(SCALE_EXTENT_KIND_MAPPING, depth) || mapper.getExtentUnsafe(SCALE_EXTENT_KIND_EFFECTIVE, depth);
}
export function getScaleLinearSpanForMapping(mapper) {
var extent = getScaleExtentForMappingUnsafe(mapper, SCALE_MAPPER_DEPTH_INNERMOST);
return extent[1] - extent[0];
}
export function getScaleLinearSpanEffective(mapper) {
var extent = mapper.getExtentUnsafe(SCALE_EXTENT_KIND_EFFECTIVE, SCALE_MAPPER_DEPTH_INNERMOST);
return extent[1] - extent[0];
}
export function initLinearScaleMapper(
// If input `null/undefined`, a mapper will be created.
mapper, initialExtent) {
var linearMapper = mapper || {};
var extendList = [];
// @ts-ignore
linearMapper._extents = extendList;
extendList[SCALE_EXTENT_KIND_EFFECTIVE] = initialExtent ? initialExtent.slice() : initExtentForUnion();
extend(linearMapper, linearScaleMapperMethods);
return linearMapper;
}
var linearScaleMapperMethods = {
needTransform: function () {
return false;
},
normalize: function (val) {
var extent = this._extents[SCALE_EXTENT_KIND_MAPPING] || this._extents[SCALE_EXTENT_KIND_EFFECTIVE];
if (extent[1] === extent[0]) {
return 0.5;
}
return (val - extent[0]) / (extent[1] - extent[0]);
},
scale: function (val) {
var extent = this._extents[SCALE_EXTENT_KIND_MAPPING] || this._extents[SCALE_EXTENT_KIND_EFFECTIVE];
return val * (extent[1] - extent[0]) + extent[0];
},
transformIn: function (val) {
return val;
},
transformOut: function (val) {
return val;
},
contain: function (val) {
// This method is typically used in axis trigger and markers.
// Users may be confused if the extent is restricted to `SCALE_EXTENT_KIND_EFFECTIVE`.
var extent = getScaleExtentForMappingUnsafe(this, null);
return val >= extent[0] && val <= extent[1];
},
getExtent: function () {
return this._extents[SCALE_EXTENT_KIND_EFFECTIVE].slice();
},
getExtentUnsafe: function (kind) {
return this._extents[kind];
},
setExtent: function (start, end) {
if (process.env.NODE_ENV !== 'production') {
assert(!this._frozen);
}
writeExtent(this._extents, SCALE_EXTENT_KIND_EFFECTIVE, start, end);
},
setExtent2: function (kind, start, end) {
if (process.env.NODE_ENV !== 'production') {
assert(!this._frozen);
}
var extentList = this._extents;
if (!extentList[kind]) {
extentList[kind] = extentList[SCALE_EXTENT_KIND_EFFECTIVE].slice();
}
writeExtent(extentList, kind, start, end);
},
freeze: function () {
if (process.env.NODE_ENV !== 'production') {
// @ts-ignore
this._frozen = true;
}
}
};
function writeExtent(extentList, kind, start, end) {
// NOTE: `NaN` should be excluded. e.g., `scaleRawExtentInfo.resultMinMax` may be `[NaN, NaN]`.
if (isValidBoundsForExtent(start, end)) {
extentList[kind][0] = start;
extentList[kind][1] = end;
} else {
if (process.env.NODE_ENV !== 'production') {
// PENDING: should use `assert` after fixing all invalid calls.
if (start != null && end != null && start <= end) {
error("Invalid setExtent call - start: " + start + ", end: " + end);
}
}
}
}
// ------ END: Linear Scale Mapper ------