blob: 26fcea5959c049d6fed643443a976057e8c777f0 [file] [log] [blame]
/**
* Complete dimensions by data (guess dimension).
*/
import * as zrUtil from 'zrender/src/core/util';
import { normalizeToArray } from '../../util/model';
var each = zrUtil.each;
var isString = zrUtil.isString;
var defaults = zrUtil.defaults;
var OTHER_DIMS = {
tooltip: 1,
label: 1,
itemName: 1
};
/**
* Complete the dimensions array, by user defined `dimension` and `encode`,
* and guessing from the data structure.
* If no 'value' dimension specified, the first no-named dimension will be
* named as 'value'.
*
* @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which
* provides not only dim template, but also default order.
* `name` of each item provides default coord name.
* [{dimsDef: []}, ...] can be specified to give names.
* @param {Array} data Data list. [[1, 2, 3], [2, 3, 4]].
* @param {Object} [opt]
* @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
* For example: ['asdf', {name, type}, ...].
* @param {Object} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}
* @param {string} [opt.extraPrefix] Prefix of name when filling the left dimensions.
* @param {string} [opt.extraFromZero] If specified, extra dim names will be:
* extraPrefix + 0, extraPrefix + extraBaseIndex + 1 ...
* If not specified, extra dim names will be:
* extraPrefix, extraPrefix + 0, extraPrefix + 1 ...
* @param {number} [opt.dimCount] If not specified, guess by the first data item.
* @return {Array.<Object>} [{
* name: string mandatory,
* coordDim: string mandatory,
* coordDimIndex: number mandatory,
* type: string optional,
* tooltipName: string optional,
* otherDims: {
* tooltip: number optional,
* label: number optional
* },
* isExtraCoord: boolean true or undefined.
* other props ...
* }]
*/
function completeDimensions(sysDims, data, opt) {
data = data || [];
opt = opt || {};
sysDims = (sysDims || []).slice();
var dimsDef = (opt.dimsDef || []).slice();
var encodeDef = zrUtil.createHashMap(opt.encodeDef);
var dataDimNameMap = zrUtil.createHashMap();
var coordDimNameMap = zrUtil.createHashMap(); // var valueCandidate;
var result = [];
var dimCount = opt.dimCount;
if (dimCount == null) {
var value0 = retrieveValue(data[0]);
dimCount = Math.max(zrUtil.isArray(value0) && value0.length || 1, sysDims.length, dimsDef.length);
each(sysDims, function (sysDimItem) {
var sysDimItemDimsDef = sysDimItem.dimsDef;
sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));
});
} // Apply user defined dims (`name` and `type`) and init result.
for (var i = 0; i < dimCount; i++) {
var dimDefItem = isString(dimsDef[i]) ? {
name: dimsDef[i]
} : dimsDef[i] || {};
var userDimName = dimDefItem.name;
var resultItem = result[i] = {
otherDims: {}
}; // Name will be applied later for avoiding duplication.
if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
// Only if `series.dimensions` is defined in option, tooltipName
// will be set, and dimension will be diplayed vertically in
// tooltip by default.
resultItem.name = resultItem.tooltipName = userDimName;
dataDimNameMap.set(userDimName, i);
}
dimDefItem.type != null && (resultItem.type = dimDefItem.type);
} // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
encodeDef.each(function (dataDims, coordDim) {
dataDims = encodeDef.set(coordDim, normalizeToArray(dataDims).slice());
each(dataDims, function (resultDimIdx, coordDimIndex) {
// The input resultDimIdx can be dim name or index.
isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));
if (resultDimIdx != null && resultDimIdx < dimCount) {
dataDims[coordDimIndex] = resultDimIdx;
applyDim(result[resultDimIdx], coordDim, coordDimIndex);
}
});
}); // Apply templetes and default order from `sysDims`.
var availDimIdx = 0;
each(sysDims, function (sysDimItem, sysDimIndex) {
var coordDim;
var sysDimItem;
var sysDimItemDimsDef;
var sysDimItemOtherDims;
if (isString(sysDimItem)) {
coordDim = sysDimItem;
sysDimItem = {};
} else {
coordDim = sysDimItem.name;
sysDimItem = zrUtil.clone(sysDimItem); // `coordDimIndex` should not be set directly.
sysDimItemDimsDef = sysDimItem.dimsDef;
sysDimItemOtherDims = sysDimItem.otherDims;
sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null;
}
var dataDims = normalizeToArray(encodeDef.get(coordDim)); // dimensions provides default dim sequences.
if (!dataDims.length) {
for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {
availDimIdx++;
}
availDimIdx < result.length && dataDims.push(availDimIdx++);
}
} // Apply templates.
each(dataDims, function (resultDimIdx, coordDimIndex) {
var resultItem = result[resultDimIdx];
applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
if (resultItem.name == null && sysDimItemDimsDef) {
resultItem.name = resultItem.tooltipName = sysDimItemDimsDef[coordDimIndex];
}
sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
});
}); // Make sure the first extra dim is 'value'.
var extra = opt.extraPrefix || 'value'; // Set dim `name` and other `coordDim` and other props.
for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};
var coordDim = resultItem.coordDim;
coordDim == null && (resultItem.coordDim = genName(extra, coordDimNameMap, opt.extraFromZero), resultItem.coordDimIndex = 0, resultItem.isExtraCoord = true);
resultItem.name == null && (resultItem.name = genName(resultItem.coordDim, dataDimNameMap));
resultItem.type == null && guessOrdinal(data, resultDimIdx) && (resultItem.type = 'ordinal');
}
return result;
function applyDim(resultItem, coordDim, coordDimIndex) {
if (OTHER_DIMS[coordDim]) {
resultItem.otherDims[coordDim] = coordDimIndex;
} else {
resultItem.coordDim = coordDim;
resultItem.coordDimIndex = coordDimIndex;
coordDimNameMap.set(coordDim, true);
}
}
function genName(name, map, fromZero) {
if (fromZero || map.get(name) != null) {
var i = 0;
while (map.get(name + i) != null) {
i++;
}
name += i;
}
map.set(name, true);
return name;
}
} // The rule should not be complex, otherwise user might not
// be able to known where the data is wrong.
var guessOrdinal = completeDimensions.guessOrdinal = function (data, dimIndex) {
for (var i = 0, len = data.length; i < len; i++) {
var value = retrieveValue(data[i]);
if (!zrUtil.isArray(value)) {
return false;
}
var value = value[dimIndex]; // Consider usage convenience, '1', '2' will be treated as "number".
// `isFinit('')` get `true`.
if (value != null && isFinite(value) && value !== '') {
return false;
} else if (isString(value) && value !== '-') {
return true;
}
}
return false;
};
function retrieveValue(o) {
return zrUtil.isArray(o) ? o : zrUtil.isObject(o) ? o.value : o;
}
export default completeDimensions;