@alicloud/cloud-charts
Version:

1,191 lines (1,136 loc) • 43 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.beautifyNumber = beautifyNumber;
exports.calcLinearColor = calcLinearColor;
exports.containsChinese = containsChinese;
exports.customFormatter = customFormatter;
exports.deepAssign = void 0;
exports.fillMissingTimestamps = fillMissingTimestamps;
exports.filterKey = filterKey;
exports.findUnitArray = findUnitArray;
exports.generateTimestamps = generateTimestamps;
exports.getAreaColors = getAreaColors;
exports.getAutoMask = getAutoMask;
exports.getDataIndexColor = getDataIndexColor;
exports.getFormatConfig = getFormatConfig;
exports.getHourlyTimestamp = getHourlyTimestamp;
exports.getParentSize = getParentSize;
exports.getRawData = getRawData;
exports.getStatusColor = getStatusColor;
exports.getStatusColorName = getStatusColorName;
exports.isInsideChina = isInsideChina;
exports.isInvalidNumber = isInvalidNumber;
exports.mapColors = mapColors;
exports.noop = noop;
exports.numberDecimal = numberDecimal;
exports.propertyAssign = propertyAssign;
exports.propertyMap = void 0;
exports.pxToNumber = pxToNumber;
exports.requestAnimationFrame = void 0;
exports.sampleDataWithNoise = sampleDataWithNoise;
exports.traverseTree = traverseTree;
exports.unitConversion = unitConversion;
exports.unitFamily = void 0;
var _tinycolor = _interopRequireDefault(require("tinycolor2"));
var _themes = _interopRequireDefault(require("../themes"));
var _log = require("./log");
var _index2 = require("../ChartProvider/index");
var _worldWithoutAntarctic = _interopRequireDefault(require("../plugins/worldmap/data/world-without-antarctic.json"));
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
exports.isEqual = _isEqual["default"];
var _isEqualWith = _interopRequireDefault(require("lodash/isEqualWith"));
exports.isEqualWith = _isEqualWith["default"];
var _merge = _interopRequireDefault(require("lodash/merge"));
exports.merge = _merge["default"];
var _colorMap = _interopRequireDefault(require("./colorMap"));
var _worldGeo$features;
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } // @ts-ignore
var requestAnimationFrame = exports.requestAnimationFrame = window && window.requestAnimationFrame;
var propertyMap = exports.propertyMap = {
axis: ['type', 'showLast', 'alias', 'sync', 'mask', 'base', 'exponent', 'values', 'range', 'min', 'max', 'minLimit', 'maxLimit', 'nice', 'ticks', 'tickMethod', 'tickCount', 'maxTickCount', 'tickInterval', 'minTickInterval', 'formatter']
};
var keyType = {
min: 'number',
max: 'number',
minLimit: 'number',
maxLimit: 'number',
tickCount: 'number'
};
/**
* 向目标对象拷贝指定的key的值
*
* @param {string[]} keys 判断的key
* @param {Object} target 目标对象
* @param {Object} source 源对象
*
* @return {Object} 目标对象
* */
function propertyAssign(keys, target, source) {
if (!source) {
return target;
}
keys.forEach(function (key) {
// 仅判断undefined的情况
if (source[key] === undefined) {
return;
}
// 忽略 tickCount: 'auto'
if (key === 'tickCount' && source[key] === 'auto') {
(0, _log.warn)('config.axis', "tickCount: 'auto' \u88AB\u66FF\u6362\u4E3A Axis.autoHide: true");
return;
}
// 将部分限制了类型的key属性转换为需要的类型
if (keyType[key] !== 'number') {
target[key] = source[key];
} else if (source[key] === null) {
// 设置null则直接赋值
target[key] = null;
} else if (!isInvalidNumber(source[key])) {
// 是数字时才赋值,否则直接跳过
target[key] = Number(source[key]);
}
// if (keyType[key] === 'number') {
// if (!isInvalidNumber(source[key])) {
// target[key] = Number(source[key]);
// }
// } else {
// target[key] = source[key];
// }
});
return target;
}
/**
* 找到对应元素的父元素的大小
*
* @param {element} element Html元素
* @param {number | string} width props中传递的width属性
* @param {number | string} height props中传递的height属性
*
* @return {number[]} 宽和高的数组
* */
function getParentSize(element, width, height) {
var w = width || '';
var h = height || '';
var parent = element && element.parentElement.parentElement;
if (parent) {
var parentStyle = window.getComputedStyle(parent);
var paddingTop = pxToNumber(parentStyle.getPropertyValue('padding-top'));
var paddingRight = pxToNumber(parentStyle.getPropertyValue('padding-right'));
var paddingBottom = pxToNumber(parentStyle.getPropertyValue('padding-bottom'));
var paddingLeft = pxToNumber(parentStyle.getPropertyValue('padding-left'));
if (!width) {
w = parent.clientWidth - paddingLeft - paddingRight;
}
if (!height) {
h = parent.clientHeight - paddingTop - paddingBottom;
}
}
return [Number(w), Number(h)];
}
/**
* 将像素字符串转为数值
*
* @param {string} px 像素字符串
*
* @return {number} 数值
* */
function pxToNumber(px) {
return Number(px.replace('px', ''));
}
/**
* 从Highcharts格式数据中找到对应index的颜色
*
* @param {array} colors 颜色数组
* @param {array} rawData Highcharts 格式的数据
* @param {number} dataIndex y轴对应的index
* */
function getDataIndexColor(colors, rawData, dataIndex) {
if (typeof colors === 'string') {
return colors;
}
var colorIndex = null;
// 找到第一个顺序值和数据中yAxis值匹配的index
rawData.some(function (d, i) {
var dataYAxisIndex = d.yAxis || 0;
if (dataYAxisIndex === dataIndex) {
colorIndex = i;
return true;
}
return false;
});
if (typeof colorIndex === 'number') {
if (Array.isArray(colors)) {
return colors[colorIndex];
}
if (typeof colors === 'function') {
return colors(rawData[colorIndex].name);
}
}
}
/** 主题关键字 */
/** 颜色映射, 主要针对状态色 */
function mapColors(colors) {
var newColors = colors;
if (typeof colors === 'string') {
newColors = colors in _colorMap["default"] ? _themes["default"][_colorMap["default"][colors]] : colors;
} else if (Array.isArray(colors)) {
newColors = colors.map(function (color) {
return color in _colorMap["default"] ? _themes["default"][_colorMap["default"][color]] : color;
});
}
return newColors;
}
/**
* 根据状态获得颜色值
*
* @param {string} status 状态字符串
*
* @return {string} 颜色值
* */
function getStatusColor(status) {
// map 放入函数内,以响应 theme 的动态变化
var statusMap = {
error: _themes["default"]['widgets-color-red'],
red: _themes["default"]['widgets-color-red'],
warning: _themes["default"]['widgets-color-orange'],
orange: _themes["default"]['widgets-color-orange'],
// 运行色和主色有区分
blue: _themes["default"]['widgets-color-blue'],
normal: _themes["default"]['widgets-color-normal'],
primary: _themes["default"]['widgets-color-primary'],
success: _themes["default"]['widgets-color-green'],
green: _themes["default"]['widgets-color-green'],
none: _themes["default"]['widgets-color-gray'],
gray: _themes["default"]['widgets-color-gray']
};
return statusMap[status] || status || statusMap.normal;
}
var statusColorMap = {
error: 'red',
warning: 'orange',
normal: 'normal',
success: 'green',
none: 'gray',
primary: 'primary',
blue: 'blue'
};
/**
* 根据状态获得颜色名称
*
* @param {string} status 状态字符串
*
* @return {string} 颜色名称
* */
function getStatusColorName(status) {
return statusColorMap[status] || status || statusColorMap.normal;
}
// 统一面积填充的渐变色逻辑
function getAreaColors(areaColors, isStack) {
return areaColors === null || areaColors === void 0 ? void 0 : areaColors.map(function (subColor) {
// 若包含自定义渐变则不处理
if (subColor.includes('l') || subColor.includes('r') || subColor.includes('p')) {
return subColor;
} else if (isStack) {
return subColor;
} else {
return "l(90) 0:" + subColor + "70 0.7:" + subColor + "66 1:" + subColor + "03";
}
});
}
/**
* 判断是否是无效数字
*
* @param v 输入值
* 增加判断V中有大写字母,目的是为了区分region地址和科学记数法
*
* @return {boolean} 是否无效数字
* */
function isInvalidNumber(v) {
return isNaN(v) || !isFinite(v) || v === '' || typeof v === 'object' || /[A-Z]/.test(v);
}
/**
* 数字格式化小数位
*
* @param {number} num 输入数字
* @param {number} decimal 小数位数,默认一位
*
* @return {string|number} 如果不是数字,返回横杠字符串。如果是数字,返回设定小数位的字符串。
* */
function numberDecimal(num, decimal) {
if (decimal === void 0) {
decimal = 1;
}
if (isInvalidNumber(num) || isInvalidNumber(decimal)) {
return num;
}
// 小数位被转换为整数且不小于0
var d = Math.max(0, Math.round(decimal));
return Math.round(Number(num) * Math.pow(10, d)) / Math.pow(10, d);
}
/**
* 数字格式化千分位
*
* @param {number} num 输入数字
* @param {number} char 分隔符,默认为逗号
*
* @return {string|number} 如果不是数字,返回横杠字符串。如果是数字,返回千分位的字符串。
* */
function beautifyNumber(num, _char) {
if (_char === void 0) {
_char = ',';
}
if (isInvalidNumber(num)) {
return num;
}
var isNegative = num < 0;
var numberArr = num.toString().split('.');
var number = numberArr[0].replace('-', '');
var result = '';
while (number.length > 3) {
result = _char + number.slice(-3) + result;
number = number.slice(0, number.length - 3);
}
if (number) {
result = number + result;
}
// fix 保留了小数位数字
if (numberArr[1]) {
result = result + "." + numberArr[1];
}
// 处理负数
if (isNegative) {
result = "-" + result;
}
return result;
}
/**
* 空函数
* */
function noop() {}
/**
* tooltip item 获取原始数据
*
* @param {object} config 图表配置项
* @param {array} rawData 挂载于 this.rawData 上的原始数据
* @param {number} item tooltip格式化函数的当前数据项
*
* @return {object} 寻找得到的原始数据,没有找到则返回空对象。
* */
function getRawData(config, rawData, item) {
if (!rawData) {
return {};
}
var originData = item.data || {};
if (config.dataType !== 'g2' && Array.isArray(rawData)) {
rawData.some(function (r) {
if (r.name === originData.type) {
// 如果原数据中定义了 facet,需要额外判定 facet 字段
if (r.facet && originData.facet !== r.facet) {
return false;
}
originData = r;
return true;
}
return false;
});
}
return originData;
}
/**
* 过滤对象中的key,常用于过滤传递给div的props,防止react invalid attribute warning
*
* @param {object} obj 过滤的对象
* @param {array} keys 过滤的键列表
*
* @return {object} 过滤后的结果
* */
function filterKey(obj, keys) {
var result = {};
Object.keys(obj).forEach(function (key) {
if (keys.indexOf(key) === -1) {
result[key] = obj[key];
}
});
return result;
}
// 内置模糊匹配
// 统一存储单位显示
var GBUnit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'];
var GBSpeedUnit = ['B/S', 'KB/S', 'MB/S', 'GB/S', 'TB/S', 'PB/S', 'EB/S', 'ZB/S'];
var GiBUnit = ['BYTE', 'KIB', 'MIB', 'GIB', 'TIB', 'PIB', 'EIB', 'ZIB'];
var GiBSpeedUnit = ['BYTE/S', 'KIB/S', 'MIB/S', 'GIB/S', 'TIB/S', 'PIB/S', 'EIB/S', 'ZIB/S'];
var unitMap = {
number: [],
disk_1000: GBUnit,
disk_1024: GiBUnit,
bandwidth_1000: GBSpeedUnit,
bandwidth_1024: GiBSpeedUnit,
money: ['¥'],
dollar: ['$'],
percent_1: ['%'],
percent_100: ['%'],
count: ['counts', 'k', 'm', 'b'],
counts: ['counts', 'k', 'm', 'b'],
time: ['ps', 'ns', 'μs', 'ms', 's'],
date: ['ms', 's', 'm', 'h', 'days', 'weeks', 'months', 'years']
};
function convertTimeUnit(value, unit, decimal) {
var resultValue = value;
var currentUnit = !unitMap['date'].includes(unit) || !unit ? 'ms' : unit;
var conversions = {
ms: 1,
s: 1000,
m: 60 * 1000,
h: 60 * 60 * 1000,
days: 24 * 60 * 60 * 1000,
weeks: 7 * 24 * 60 * 60 * 1000,
months: 30 * 24 * 60 * 60 * 1000,
// 这里假设一个月为30天
years: 365 * 24 * 60 * 60 * 1000 // 这里假设一年为365天
};
if (currentUnit !== 'ms') {
resultValue = resultValue * conversions[currentUnit];
}
var resultUnit = currentUnit;
if (resultValue >= conversions.years) {
resultValue = numberDecimal(resultValue / conversions.years, decimal);
resultUnit = 'y';
} else if (resultValue >= conversions.months) {
resultValue = numberDecimal(resultValue / conversions.months, decimal);
resultUnit = 'months';
} else if (resultValue >= conversions.weeks) {
resultValue = numberDecimal(resultValue / conversions.weeks, decimal);
resultUnit = 'weeks';
} else if (resultValue >= conversions.days) {
resultValue = numberDecimal(resultValue / conversions.days, decimal);
resultUnit = 'days';
} else if (resultValue >= conversions.h) {
resultValue = numberDecimal(resultValue / conversions.h, decimal);
resultUnit = 'h';
} else if (resultValue >= conversions.m) {
resultValue = numberDecimal(resultValue / conversions.m, decimal);
resultUnit = 'm';
} else if (resultValue >= conversions.s) {
resultValue = numberDecimal(resultValue / conversions.s, decimal);
resultUnit = 's';
} else {
resultUnit = 'ms';
}
return {
value: resultValue,
unit: resultUnit,
formattedValue: "" + resultValue + resultUnit
};
}
var unitFamily = exports.unitFamily = {
disk_1000: {
defaultUnit: 'B/S',
units: GBSpeedUnit,
upgradeFactor: 1000,
otherUnits: {
'BYTE': ['bytes']
}
},
disk_1024: {
defaultUnit: 'BYTE',
units: GiBUnit,
upgradeFactor: 1024,
otherUnits: {
'BYTE': ['bytes']
}
},
bandwidth_1000: {
defaultUnit: '',
units: GBSpeedUnit,
upgradeFactor: 1000,
otherUnits: {
'BYTE': ['bytes']
}
},
bandwidth_1024: {
defaultUnit: '¥',
units: GiBSpeedUnit,
upgradeFactor: 1024,
otherUnits: {
'BYTE/S': ['bytes/s']
}
},
money: {
defaultUnit: '¥',
units: ['¥'],
upgradeFactor: 1,
otherUnits: null
},
percent_1: {
defaultUnit: '%',
units: ['%'],
upgradeFactor: 100,
otherUnits: null
},
percent_100: {
defaultUnit: '%',
units: ['%'],
upgradeFactor: 1,
otherUnits: null
},
countFrequency: {
defaultUnit: 'count/s',
units: ['count/s', 'count/m', 'count/h', 'count/d'],
upgradeFactor: 1000,
otherUnits: {
'count/s': ['counts/s'],
'count/m': ['counts/m'],
'count/h': ['counts/h']
}
},
countRate: {
defaultUnit: 'count/s',
units: ['count/s', 'k/s', 'm/s', 'b/s'],
upgradeFactor: 1000,
otherUnits: {
counts: ['', 'count']
}
},
count: {
defaultUnit: 'count',
units: ['count', 'k', 'm', 'b'],
upgradeFactor: 1000,
otherUnits: {
counts: ['', 'counts']
}
},
time: {
defaultUnit: 's',
upgradeFactor: {
s: 1000,
m: 60,
h: 24
// days: 1,
// weeks: 7,
// months: 12,
// years: 12
},
units: ['ps', 'ns', 'μs', 'ms', 's', 'm', 'h'],
otherUnits: null
}
};
/**
* 自定义格式化函数,支持 单位、小数位、千分位 处理
* 包含云体系下的单位处理
* valueType 表示进位方式
* unit 为当前单位, 默认为当前类型的最小单位
* needUnitTransform 为是否需要转换
* unitTransformTo 为目标单位
* 如:
* disk - b、kb、mb
* bandwidth - b/s、kb/s、mb/s
* money - ¥
* percent - %
* count - count、k、m、b
* time - ms、s
* */
function customFormatter(config) {
var unit = config.unit,
_config$decimal = config.decimal,
decimal = _config$decimal === void 0 ? 1 : _config$decimal,
_config$grouping = config.grouping,
grouping = _config$grouping === void 0 ? true : _config$grouping,
needUnitTransform = config.needUnitTransform,
unitTransformTo = config.unitTransformTo,
valueType = config.valueType,
_config$hideZeroUnit = config.hideZeroUnit,
hideZeroUnit = _config$hideZeroUnit === void 0 ? false : _config$hideZeroUnit,
_config$customCarryUn = config.customCarryUnits,
customCarryUnits = _config$customCarryUn === void 0 ? [] : _config$customCarryUn,
customCarryThreshold = config.customCarryThreshold,
_config$addonTextAfte = config.addonTextAfter,
addonTextAfter = _config$addonTextAfte === void 0 ? '' : _config$addonTextAfte;
if (!unit && (decimal === undefined || decimal === null) && !grouping && !needUnitTransform) {
return null;
}
return function (v) {
// 柱状图极端情况特殊处理
if (typeof v === 'string' && v.startsWith('widgets-pad-')) {
return '';
}
var result = v;
var newUnit = unit || '';
if (isInvalidNumber(v)) {
return "" + v + newUnit;
}
if (needUnitTransform && (unit || valueType)) {
if (valueType === 'percent_1') {
result = result * 100;
}
var _unitConversion = unitConversion(result, unit, decimal, unitTransformTo, valueType, customCarryUnits, customCarryThreshold, addonTextAfter),
value = _unitConversion.value,
transformUnit = _unitConversion.unit;
result = value;
newUnit = transformUnit;
// count计数时不显示单位
if (valueType === 'count' && newUnit === 'counts') {
newUnit = '';
}
}
// 小数位
result = numberDecimal(result, decimal);
// 千分位
if (grouping || ['money', 'dollar', 'count'].includes(valueType)) {
result = beautifyNumber(result, typeof grouping === 'boolean' ? ',' : grouping);
}
if (hideZeroUnit && Number(result) === 0) {
newUnit = '';
}
return ['money', 'dollar'].includes(valueType) ? "" + newUnit + result : "" + result + newUnit;
};
}
function findUnitArray(input, valueType) {
if (valueType) {
// 定义待查找的数组列表
var unitArrays = unitMap[valueType];
// 遍历待查找的数组列表
if (unitArrays !== null && unitArrays !== void 0 && unitArrays.includes(input)) {
// 如果输入值存在于当前数组中,返回该数组
return unitArrays;
}
} else {
var targetArray = [];
Object.keys(unitMap).forEach(function (key) {
if (unitMap[key].includes(input)) {
targetArray = unitMap[key];
}
});
return targetArray;
}
// 若遍历完所有数组仍未找到匹配项,返回 []
return [];
}
/**
* 统一进位单位格式化
* */
function unitConversion(originValue, unit, decimal, unitTransformTo, valueType, customCarryUnits, customCarryThreshold, addonTextAfter) {
var isNegative = originValue < 0;
var value = Math.abs(originValue);
var suffixUnit = addonTextAfter || '';
// 增加自定义进位
if (valueType === 'custom') {
var threshold = customCarryThreshold || 1000;
var units = typeof customCarryUnits === 'string' ? customCarryUnits.split(',') : customCarryUnits || ["", "k", "m", "b"];
var currentUnit = unit || units[0] || '';
var finalUnit = unit || '';
var index = units.indexOf(currentUnit);
while (value >= threshold && index < units.length - 1) {
value /= threshold;
index++;
}
finalUnit = units[index] || '';
var finalValue = numberDecimal(value, decimal);
return {
value: typeof finalValue === 'number' ? isNegative ? -finalValue : finalValue : '-',
unit: finalUnit + suffixUnit
};
}
if (valueType === 'date') {
var _convertTimeUnit;
var _ref = (_convertTimeUnit = convertTimeUnit(value, unit, decimal)) !== null && _convertTimeUnit !== void 0 ? _convertTimeUnit : {},
_finalValue = _ref.value,
_finalUnit = _ref.unit;
return {
value: typeof _finalValue === 'number' ? isNegative ? -_finalValue : _finalValue : '-',
unit: (_finalUnit !== null && _finalUnit !== void 0 ? _finalUnit : '') + suffixUnit
};
} else {
var _currentUnit = unit ? unit.toUpperCase() : unitMap[valueType][0];
// 只有流量、存储单位大写
if (_currentUnit && !['disk_1000', 'disk_1024', 'bandwidth_1000', 'bandwidth_1024'].includes(valueType)) {
_currentUnit = _currentUnit.toLowerCase();
}
// 单位的特殊处理,后期统一从unitFamily中取
if (valueType === 'time') {
_currentUnit = unit !== null && unit !== void 0 ? unit : 's';
}
var _units = findUnitArray(_currentUnit, valueType);
var _finalUnit2 = unit;
var _threshold = valueType !== null && valueType !== void 0 && valueType.includes('1024') ? 1024 : 1000;
var _index = _units.indexOf(_currentUnit);
if (_index === -1) {
return {
value: originValue,
unit: unit + suffixUnit
};
}
if (unitTransformTo) {
var UpUnitTransformTot = unitTransformTo.toUpperCase();
var targetUnitIndex = _units.indexOf(UpUnitTransformTot);
if (_index === targetUnitIndex) {
return {
value: originValue,
unit: unit + suffixUnit
};
}
var distance = Math.abs(_index - targetUnitIndex);
if (_index > targetUnitIndex) {
value *= Math.pow(_threshold, distance);
} else {
value /= Math.pow(_threshold, distance);
}
_finalUnit2 = unitTransformTo;
}
if (!unitTransformTo) {
while (value >= _threshold && _index < _units.length - 1) {
value /= _threshold;
_index++;
}
_finalUnit2 = _units[_index];
}
if (valueType === 'count' && _finalUnit2 === 'counts') {
_finalUnit2 = '';
}
var _finalValue2 = numberDecimal(value, decimal);
return {
value: typeof _finalValue2 === 'number' ? isNegative ? -_finalValue2 : _finalValue2 : '-',
unit: _finalUnit2 + suffixUnit
};
}
}
function generateScaledArray(dataSize) {
var max = 0.75;
var min = 0.1;
var scaleArray = [max];
var distance = 0.1;
var mean = (0.4 - min) / (dataSize - 5);
// 前五个分差为0.1
for (var i = 1; i < 6; i++) {
scaleArray.push(max - i * distance);
}
// 后面均分
for (var _i = 6; _i < dataSize - 1; _i++) {
scaleArray.push(0.4 - mean * (_i - 5));
}
scaleArray.push(min);
return scaleArray;
}
/**
* 获取指定颜色的顺序色
* *
* @param {string} primaryColor 指定颜色
* @param {string} backgroundColor 当前背景色
* @param {number} linearCount 顺序色个数
* @param {string} type 是否为中心取色
* */
function calcLinearColor(primaryColor, backgroundColor, linearCount, type, needDistribution) {
var linear = [];
var front = (0, _tinycolor["default"])(primaryColor);
var _front$toHsv = front.toHsv(),
h = _front$toHsv.h,
s = _front$toHsv.s,
v = _front$toHsv.v;
var _tinycolor$toHsv = (0, _tinycolor["default"])(backgroundColor).toHsv(),
backValue = _tinycolor$toHsv.v;
var isLight = backValue > 0.5;
var whiteV = (0, _tinycolor["default"])("#ffffff").toHsv().v;
var count = linearCount + 1;
// 中心取色逻辑
if (type === 'center') {
var colorString;
for (var i = 1; i < count + 1; i++) {
colorString = (0, _tinycolor["default"])({
h: h,
s: Math.round(i * s * 100 / count) + 1,
v: Math.round((i * (v - whiteV) / count + whiteV) * 100)
}).toHexString();
if (i % 2 === 0) {
linear.push(colorString);
} else if (colorString === primaryColor) {
linear.push(colorString);
}
}
for (var _i2 = count; _i2 > Math.floor(count / 2) + 1; _i2--) {
colorString = _tinycolor["default"].mix("#000000", primaryColor, (_i2 - 2) * 10).toHexString();
linear.push(colorString);
}
if (linear[Math.floor(linearCount / 2)] !== primaryColor) {
linear[Math.floor(linearCount / 2)] = primaryColor;
}
} else {
// 如果数量超过10,则有限调整前5的颜色梯度差值,避免过于相近
// 同时需要防止颜色过于趋向于白/黑
if (needDistribution) {
var distributionArray = generateScaledArray(count);
// console.log(distributionArray)
for (var _i3 = count - 1; _i3 > 0; _i3--) {
var _colorString = void 0;
// 亮色模式
if (isLight) {
_colorString = (0, _tinycolor["default"])({
h: h,
s: distributionArray[count - _i3 - 1] * s * 100,
// v: v * 100,
v: Math.round((_i3 * (v - backValue) / count + backValue) * 100)
}).toHexString();
} else {
// 暗色模式
_colorString = _tinycolor["default"].mix(backgroundColor, primaryColor, distributionArray[count - _i3 - 1] * 100).toHexString();
}
linear.push(_colorString);
}
} else {
for (var _i4 = count - 1; _i4 > 0; _i4--) {
var _colorString2 = void 0;
// 亮色模式
if (isLight) {
_colorString2 = (0, _tinycolor["default"])({
h: h,
s: Math.round(_i4 / count * s * 100),
v: Math.round((_i4 * (v - backValue) / count + backValue) * 100)
}).toHexString();
} else {
// 暗色模式
_colorString2 = _tinycolor["default"].mix(backgroundColor, primaryColor, _i4 * 10).toHexString();
}
linear.push(_colorString2);
}
}
}
return linear;
}
/**
* 递归遍历树节点
* */
function traverseTree(node, itemFunction) {
if (node.children) {
node.children.map(function (el) {
itemFunction && itemFunction(el);
traverseTree(el, itemFunction);
});
}
return node;
}
// util需要抽取出来
var isObjectLike = function isObjectLike(value) {
/**
* isObjectLike({}) => true
* isObjectLike([1, 2, 3]) => true
* isObjectLike(Function) => false
*/
return typeof value === 'object' && value !== null;
};
var isPlainObject = function isPlainObject(value) {
/**
* isObjectLike(new Foo) => false
* isObjectLike([1, 2, 3]) => false
* isObjectLike({ x: 0, y: 0 }) => true
*/
if (!isObjectLike(value) || !isType(value, 'Object')) {
return false;
}
var proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(value) === proto;
};
var MAX_MIX_LEVEL = 5; // 最大比对层级
var toString = {}.toString;
// 类型检测
var isType = function isType(value, type) {
return toString.call(value) === '[object ' + type + ']';
};
var isArray = function isArray(value) {
return isType(value, 'Array');
};
/***
* @param {any} dist
* @param {any} src
* @param {number} level 当前层级
* @param {number} maxLevel 最大层级
*/
var deep = function deep(dist, src, level, maxLevel) {
level = level || 0;
maxLevel = maxLevel || MAX_MIX_LEVEL;
for (var _key in src) {
if (Object.prototype.hasOwnProperty.call(src, _key)) {
var value = src[_key];
if (!value) {
// null 、 undefined 等情况直接赋值
dist[_key] = value;
} else {
if (isPlainObject(value)) {
if (!isPlainObject(dist[_key])) {
dist[_key] = {};
}
if (level < maxLevel) {
deep(dist[_key], value, level + 1, maxLevel);
} else {
// 层级过深直接赋值,性能问题
dist[_key] = src[_key];
}
} else if (isArray(value)) {
dist[_key] = [];
dist[_key] = dist[_key].concat(value);
} else {
dist[_key] = value;
}
}
}
}
};
/**
* deepAssign 功能类似 deepMix
* 不同点在于 deepAssign 会将 null undefined 等类型直接覆盖给 source
*/
var deepAssign = exports.deepAssign = function deepAssign(rst) {
for (var i = 0; i < (arguments.length <= 1 ? 0 : arguments.length - 1); i += 1) {
deep(rst, i + 1 < 1 || arguments.length <= i + 1 ? undefined : arguments[i + 1]);
}
return rst;
};
// 判断一个字符串中是否包含中文字符
function containsChinese(str) {
return /[\u4e00-\u9fa5]/.test(str);
}
// 均值采样函数
function sampleDataWithNoise(chartData, sampleRate, options) {
if (sampleRate === void 0) {
sampleRate = 0.5;
}
/**
* 输入的数字数组
* sampleRate: 采样率,取值范围为 (0, 1]
* 返回值: 采样后的数组,同时尽可能保留噪声数据
*/
if (sampleRate <= 0 || sampleRate > 1) {
throw new Error("Sample rate must be between 0 and 1.");
}
// 确保采样率不为1时执行采样逻辑,否则直接返回原数组
if (sampleRate < 1) {
// 定义一个简单的噪声检测逻辑,这里以数据点与前后点差值的绝对值超过平均差值的两倍作为噪声的简单判断
var avgDiff = calculateAverageDifference(chartData);
var noiseThreshold = avgDiff * 2;
// 筛选出噪声数据
var noiseIndices = chartData.map(function (value, index, array) {
return {
value: value,
index: index,
isNoise: index > 0 && index < array.length - 1 ? Math.abs(value - array[index - 1]) > noiseThreshold || Math.abs(value - array[index + 1]) > noiseThreshold : false // 边界处理
};
}).filter(function (item) {
return item.isNoise;
}).map(function (item) {
return item.index;
});
// 采样逻辑,优先保留噪声数据,再根据采样率采样其他数据
var sampledData = [];
var includedNoise = new Set();
// 先加入噪声数据
for (var _iterator = _createForOfIteratorHelperLoose(noiseIndices), _step; !(_step = _iterator()).done;) {
var index = _step.value;
if (!includedNoise.has(index)) {
sampledData.push(chartData[index]);
includedNoise.add(index);
}
}
// 根据采样率采样剩余数据
// 保留起始点和结束点
for (var i = 0; i < chartData.length; i++) {
if (!includedNoise.has(i)) {
if (Math.random() < sampleRate) {
sampledData.push(chartData[i]);
}
}
}
// 保证数据的顺序性,如果需要的话,这里可以进行排序,但通常保留原序列的相对顺序较好
return sampledData;
} else {
return [].concat(chartData);
}
}
function calculateAverageDifference(chartData) {
var sumOfDifferences = 0;
for (var i = 1; i < chartData.length; i++) {
sumOfDifferences += Math.abs(chartData[i] - chartData[i - 1]);
}
return chartData.length > 1 ? sumOfDifferences / (chartData.length - 1) : 0;
}
var chinaBorderGeoJSON = _worldWithoutAntarctic["default"] === null || _worldWithoutAntarctic["default"] === void 0 ? void 0 : (_worldGeo$features = _worldWithoutAntarctic["default"].features) === null || _worldGeo$features === void 0 ? void 0 : _worldGeo$features.find(function (item) {
var _item$properties;
return ((_item$properties = item.properties) === null || _item$properties === void 0 ? void 0 : _item$properties.name) === 'China';
});
// 点在多边形内的算法(射线法)
function pointInPolygon(point, polygon) {
var x = point[0],
y = point[1];
var inside = false;
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
var _polygon$i = polygon[i],
xi = _polygon$i[0],
yi = _polygon$i[1];
var _polygon$j = polygon[j],
xj = _polygon$j[0],
yj = _polygon$j[1];
var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}
/**
* 判断一个地点是否在中国境内
* @param latitude number 维度
* @param longitude number 经度
*/
function isInsideChina(latitude, longitude) {
if (!chinaBorderGeoJSON) return false;
// 遍历GeoJSON中的每个多边形,检查点是否在其中一个多边形内
for (var _iterator2 = _createForOfIteratorHelperLoose(chinaBorderGeoJSON.geometry.coordinates), _step2; !(_step2 = _iterator2()).done;) {
var polygon = _step2.value;
if (pointInPolygon([longitude, latitude], polygon[0])) {
return true; // 点在多边形内,即在中国境内
}
}
return false; // 点不在任何多边形内,即不在中国境内
}
var SECOND_MS = 1000;
var MINUTE_MS = 60 * 1000;
var HOUR_MS = 59 * 60 * 1000;
var DAY_MS = 22 * HOUR_MS;
var YEAR_MS = 365 * DAY_MS;
// 跨度判定列表:大于半年、大于28天、大于22小时、大于59分钟、大于一分钟、(小于分钟)
// todo后期改为跨度是否跨天/跨年/跨月判定
var timeList = [0.51 * YEAR_MS, 28 * DAY_MS, DAY_MS, HOUR_MS, MINUTE_MS, SECOND_MS];
function getTimeIndex(t) {
for (var i = 0; i < timeList.length; i++) {
if (t >= timeList[i]) {
return i;
}
}
return timeList.length;
}
// 取数据的跨度和间距两种值,跨度决定上限,间距决定下限。
function getAutoMask(def, data, language) {
if (data.length < 2) {
return (0, _index2.getText)('defaultMask', language, null);
}
// 假设数据是升序的,且传入为 Date 能识别的格式
data === null || data === void 0 ? void 0 : data.sort(function (a, b) {
return a[0] - b[0];
});
// 只取第一、二个元素的间距
var min = new Date(data[0][0]).getTime();
var minFirst = new Date(data[1][0]).getTime();
var max = new Date(data[data.length - 1][0]).getTime();
if (isNaN(min) || isNaN(max) || isNaN(minFirst)) {
return (0, _index2.getText)('defaultMask', language, null);
}
var span = max - min; // 间隔
var interval = def.tickInterval || minFirst - min; // 跨度
var spanIndex = getTimeIndex(span);
var intervalIndex = getTimeIndex(interval);
var maskMap = (0, _index2.getText)('timeMask', language, null);
// 如果记录表中没有记录,则使用默认 mask
return maskMap[intervalIndex][spanIndex] || (0, _index2.getText)('defaultMask', language, null);
}
// 获取时间戳刻度
function getHourlyTimestamp(timestamp) {
var date = new Date(timestamp);
date.setMinutes(0, 0, 0); // 设置分钟、秒和毫秒为0
return date.getTime();
}
function generateTimestamps(start, end, interval, showLast, showInteger) {
var timestamps = [];
var newStart = showInteger ? getHourlyTimestamp(start) : start;
var newEnd = showInteger ? getHourlyTimestamp(end) : end;
for (var i = newStart; i <= newEnd; i += interval) {
timestamps.push(i);
}
if (showLast && !timestamps.includes(end) && end) {
timestamps.push(end);
}
return timestamps;
}
// 根据config获取进位相关配置项
function getFormatConfig(config) {
var _config$yAxis, _config$legend, _config$legend2, _config$legend3, _config$legend4, _config$legend5, _config$legend6;
if (typeof config.yAxis === 'object' && !Array.isArray(config.yAxis) && config !== null && config !== void 0 && (_config$yAxis = config.yAxis) !== null && _config$yAxis !== void 0 && _config$yAxis.needUnitTransform && typeof config.legend !== 'boolean' && ((_config$legend = config.legend) === null || _config$legend === void 0 ? void 0 : _config$legend.needUnitTransform) === undefined) {
var _config$legend$needUn, _config$yAxis2, _config$legend$unit, _config$yAxis3, _config$legend$unitTr, _config$yAxis4, _config$legend$valueT, _config$yAxis5, _config$legend$custom, _config$yAxis6, _config$legend$custom2, _config$yAxis7, _config$legend$addonT, _config$yAxis8;
config.legend.needUnitTransform = (_config$legend$needUn = config.legend.needUnitTransform) !== null && _config$legend$needUn !== void 0 ? _config$legend$needUn : config === null || config === void 0 ? void 0 : (_config$yAxis2 = config.yAxis) === null || _config$yAxis2 === void 0 ? void 0 : _config$yAxis2.needUnitTransform;
config.legend.unit = (_config$legend$unit = config.legend.unit) !== null && _config$legend$unit !== void 0 ? _config$legend$unit : config === null || config === void 0 ? void 0 : (_config$yAxis3 = config.yAxis) === null || _config$yAxis3 === void 0 ? void 0 : _config$yAxis3.unit;
config.legend.unitTransformTo = (_config$legend$unitTr = config.legend.unitTransformTo) !== null && _config$legend$unitTr !== void 0 ? _config$legend$unitTr : config === null || config === void 0 ? void 0 : (_config$yAxis4 = config.yAxis) === null || _config$yAxis4 === void 0 ? void 0 : _config$yAxis4.unitTransformTo;
config.legend.valueType = (_config$legend$valueT = config.legend.valueType) !== null && _config$legend$valueT !== void 0 ? _config$legend$valueT : config === null || config === void 0 ? void 0 : (_config$yAxis5 = config.yAxis) === null || _config$yAxis5 === void 0 ? void 0 : _config$yAxis5.valueType;
config.legend.customCarryUnits = (_config$legend$custom = config.legend.customCarryUnits) !== null && _config$legend$custom !== void 0 ? _config$legend$custom : config === null || config === void 0 ? void 0 : (_config$yAxis6 = config.yAxis) === null || _config$yAxis6 === void 0 ? void 0 : _config$yAxis6.customCarryUnits;
config.legend.customCarryThreshold = (_config$legend$custom2 = config.legend.customCarryThreshold) !== null && _config$legend$custom2 !== void 0 ? _config$legend$custom2 : config === null || config === void 0 ? void 0 : (_config$yAxis7 = config.yAxis) === null || _config$yAxis7 === void 0 ? void 0 : _config$yAxis7.customCarryThreshold;
config.legend.addonTextAfter = (_config$legend$addonT = config.legend.addonTextAfter) !== null && _config$legend$addonT !== void 0 ? _config$legend$addonT : config === null || config === void 0 ? void 0 : (_config$yAxis8 = config.yAxis) === null || _config$yAxis8 === void 0 ? void 0 : _config$yAxis8.addonTextAfter;
}
if (typeof config.legend === 'object') {
var _config$legend$groupi, _config$yAxis9, _config$legend$decima, _config$yAxis10;
config.legend.grouping = (_config$legend$groupi = config.legend.grouping) !== null && _config$legend$groupi !== void 0 ? _config$legend$groupi : config === null || config === void 0 ? void 0 : (_config$yAxis9 = config.yAxis) === null || _config$yAxis9 === void 0 ? void 0 : _config$yAxis9.grouping;
config.legend.decimal = (_config$legend$decima = config.legend.decimal) !== null && _config$legend$decima !== void 0 ? _config$legend$decima : config === null || config === void 0 ? void 0 : (_config$yAxis10 = config.yAxis) === null || _config$yAxis10 === void 0 ? void 0 : _config$yAxis10.decimal;
}
// 进位相关配置项
var formatConfig;
// 当legend中配置了单位相关信息时,直接使用tooltip的配置项,否则使用y轴配置项
if (typeof (config === null || config === void 0 ? void 0 : config.legend) === 'object' && (config !== null && config !== void 0 && (_config$legend2 = config.legend) !== null && _config$legend2 !== void 0 && _config$legend2.valueType || config !== null && config !== void 0 && (_config$legend3 = config.legend) !== null && _config$legend3 !== void 0 && _config$legend3.unit || config !== null && config !== void 0 && (_config$legend4 = config.legend) !== null && _config$legend4 !== void 0 && _config$legend4.needUnitTransform || config !== null && config !== void 0 && (_config$legend5 = config.legend) !== null && _config$legend5 !== void 0 && _config$legend5.unitTransformTo || config !== null && config !== void 0 && (_config$legend6 = config.legend) !== null && _config$legend6 !== void 0 && _config$legend6.decimal)) {
formatConfig = config.legend;
} else if (Array.isArray(config.yAxis) && config.yAxis.length >= 2) {
// 双轴
formatConfig = config.yAxis;
} else if (Array.isArray(config.yAxis)) {
var _config$yAxis$, _config$yAxis11;
formatConfig = (_config$yAxis$ = config === null || config === void 0 ? void 0 : (_config$yAxis11 = config.yAxis) === null || _config$yAxis11 === void 0 ? void 0 : _config$yAxis11[0]) !== null && _config$yAxis$ !== void 0 ? _config$yAxis$ : {};
} else {
var _config$yAxis12;
formatConfig = (_config$yAxis12 = config === null || config === void 0 ? void 0 : config.yAxis) !== null && _config$yAxis12 !== void 0 ? _config$yAxis12 : {};
}
return formatConfig;
}
/**
* fillMissingTimestamps 数据补齐功能
*/
function fillMissingTimestamps(input, fillValue, tickInterval) {
if (fillValue === void 0) {
fillValue = null;
}
// 收集所有时间戳并计算最小间隔
var allTimestamps = input.flatMap(function (series) {
return series.data.map(function (d) {
return d[0];
});
});
var sortedTimestamps = [].concat(new Set(allTimestamps)).sort(function (a, b) {
return a - b;
});
// 计算最小时间间隔
var minInterval = Infinity;
if (tickInterval) {
minInterval = tickInterval;
} else {
for (var i = 1; i < sortedTimestamps.length; i++) {
var interval = sortedTimestamps[i] - sortedTimestamps[i - 1];
minInterval = Math.min(minInterval, interval);
}
}
// 生成完整时间序列
var start = Math.min.apply(Math, sortedTimestamps);
var end = Math.max.apply(Math, sortedTimestamps);
var completeTimestamps = [];
for (var t = start; t <= end; t += minInterval || 1) {
completeTimestamps.push(t);
}
// 填充缺失数据
return input.map(function (series) {
var valueMap = new Map(series.data.map(function (_ref2) {
var t = _ref2[0],
v = _ref2[1];
return [t, v];
}));
return {
name: series.name,
data: completeTimestamps.map(function (t) {
var _valueMap$get;
return [t, (_valueMap$get = valueMap.get(t)) !== null && _valueMap$get !== void 0 ? _valueMap$get : fillValue];
})
};
});
}