324 lines
12 KiB
JavaScript
324 lines
12 KiB
JavaScript
|
|
/*
|
|
* 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 _util = require("zrender/lib/core/util");
|
|
|
|
var createHashMap = _util.createHashMap;
|
|
var each = _util.each;
|
|
var isString = _util.isString;
|
|
var defaults = _util.defaults;
|
|
var extend = _util.extend;
|
|
var isObject = _util.isObject;
|
|
var clone = _util.clone;
|
|
|
|
var _model = require("../../util/model");
|
|
|
|
var normalizeToArray = _model.normalizeToArray;
|
|
|
|
var _sourceHelper = require("./sourceHelper");
|
|
|
|
var guessOrdinal = _sourceHelper.guessOrdinal;
|
|
var BE_ORDINAL = _sourceHelper.BE_ORDINAL;
|
|
|
|
var Source = require("../Source");
|
|
|
|
var _dimensionHelper = require("./dimensionHelper");
|
|
|
|
var OTHER_DIMENSIONS = _dimensionHelper.OTHER_DIMENSIONS;
|
|
|
|
var DataDimensionInfo = require("../DataDimensionInfo");
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* @deprecated
|
|
* Use `echarts/data/helper/createDimensions` instead.
|
|
*/
|
|
|
|
/**
|
|
* @see {module:echarts/test/ut/spec/data/completeDimensions}
|
|
*
|
|
* This method builds the relationship between:
|
|
* + "what the coord sys or series requires (see `sysDims`)",
|
|
* + "what the user defines (in `encode` and `dimensions`, see `opt.dimsDef` and `opt.encodeDef`)"
|
|
* + "what the data source provids (see `source`)".
|
|
*
|
|
* Some guess strategy will be adapted if user does not define something.
|
|
* 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.
|
|
* properties: 'name', 'type', 'displayName'.
|
|
* `name` of each item provides default coord name.
|
|
* [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and
|
|
* provide dims count that the sysDim required.
|
|
* [{ordinalMeta}] can be specified.
|
|
* @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)
|
|
* @param {Object} [opt]
|
|
* @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
|
|
* For example: ['asdf', {name, type}, ...].
|
|
* @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}
|
|
* @param {Function} [opt.encodeDefaulter] Called if no `opt.encodeDef` exists.
|
|
* If not specified, auto find the next available data dim.
|
|
* param source {module:data/Source}
|
|
* param dimCount {number}
|
|
* return {Object} encode Never be `null/undefined`.
|
|
* @param {string} [opt.generateCoord] Generate coord dim with the given name.
|
|
* If not specified, extra dim names will be:
|
|
* 'value', 'value0', 'value1', ...
|
|
* @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.
|
|
* If `generateCoordCount` specified, the generated dim names will be:
|
|
* `generateCoord` + 0, `generateCoord` + 1, ...
|
|
* can be Infinity, indicate that use all of the remain columns.
|
|
* @param {number} [opt.dimCount] If not specified, guess by the first data item.
|
|
* @return {Array.<module:data/DataDimensionInfo>}
|
|
*/
|
|
function completeDimensions(sysDims, source, opt) {
|
|
if (!Source.isInstance(source)) {
|
|
source = Source.seriesDataToSource(source);
|
|
}
|
|
|
|
opt = opt || {};
|
|
sysDims = (sysDims || []).slice();
|
|
var dimsDef = (opt.dimsDef || []).slice();
|
|
var dataDimNameMap = createHashMap();
|
|
var coordDimNameMap = createHashMap(); // var valueCandidate;
|
|
|
|
var result = [];
|
|
var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount); // Apply user defined dims (`name` and `type`) and init result.
|
|
|
|
for (var i = 0; i < dimCount; i++) {
|
|
var dimDefItem = dimsDef[i] = extend({}, isObject(dimsDef[i]) ? dimsDef[i] : {
|
|
name: dimsDef[i]
|
|
});
|
|
var userDimName = dimDefItem.name;
|
|
var resultItem = result[i] = new DataDimensionInfo(); // Name will be applied later for avoiding duplication.
|
|
|
|
if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
|
|
// Only if `series.dimensions` is defined in option
|
|
// displayName, will be set, and dimension will be diplayed vertically in
|
|
// tooltip by default.
|
|
resultItem.name = resultItem.displayName = userDimName;
|
|
dataDimNameMap.set(userDimName, i);
|
|
}
|
|
|
|
dimDefItem.type != null && (resultItem.type = dimDefItem.type);
|
|
dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
|
|
}
|
|
|
|
var encodeDef = opt.encodeDef;
|
|
|
|
if (!encodeDef && opt.encodeDefaulter) {
|
|
encodeDef = opt.encodeDefaulter(source, dimCount);
|
|
}
|
|
|
|
encodeDef = createHashMap(encodeDef); // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
|
|
|
|
encodeDef.each(function (dataDims, coordDim) {
|
|
dataDims = normalizeToArray(dataDims).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
|
|
// `{encode: {x: -1, y: 1}}`. Should not filter anything in
|
|
// this case.
|
|
|
|
if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
|
|
encodeDef.set(coordDim, false);
|
|
return;
|
|
}
|
|
|
|
var validDataDims = encodeDef.set(coordDim, []);
|
|
each(dataDims, function (resultDimIdx, idx) {
|
|
// The input resultDimIdx can be dim name or index.
|
|
isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));
|
|
|
|
if (resultDimIdx != null && resultDimIdx < dimCount) {
|
|
validDataDims[idx] = resultDimIdx;
|
|
applyDim(result[resultDimIdx], coordDim, idx);
|
|
}
|
|
});
|
|
}); // 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;
|
|
var ordinalMeta = sysDimItem.ordinalMeta;
|
|
sysDimItem.ordinalMeta = null;
|
|
sysDimItem = clone(sysDimItem);
|
|
sysDimItem.ordinalMeta = ordinalMeta; // `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 = encodeDef.get(coordDim); // negative resultDimIdx means no need to mapping.
|
|
|
|
if (dataDims === false) {
|
|
return;
|
|
}
|
|
|
|
var dataDims = normalizeToArray(dataDims); // 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) {
|
|
var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
|
|
!isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {
|
|
name: sysDimItemDimsDefItem
|
|
});
|
|
resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
|
|
resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
|
|
} // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
|
|
|
|
|
|
sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
|
|
});
|
|
});
|
|
|
|
function applyDim(resultItem, coordDim, coordDimIndex) {
|
|
if (OTHER_DIMENSIONS.get(coordDim) != null) {
|
|
resultItem.otherDims[coordDim] = coordDimIndex;
|
|
} else {
|
|
resultItem.coordDim = coordDim;
|
|
resultItem.coordDimIndex = coordDimIndex;
|
|
coordDimNameMap.set(coordDim, true);
|
|
}
|
|
} // Make sure the first extra dim is 'value'.
|
|
|
|
|
|
var generateCoord = opt.generateCoord;
|
|
var generateCoordCount = opt.generateCoordCount;
|
|
var fromZero = generateCoordCount != null;
|
|
generateCoordCount = generateCoord ? generateCoordCount || 1 : 0;
|
|
var extra = generateCoord || 'value'; // Set dim `name` and other `coordDim` and other props.
|
|
|
|
for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
|
|
var resultItem = result[resultDimIdx] = result[resultDimIdx] || new DataDimensionInfo();
|
|
var coordDim = resultItem.coordDim;
|
|
|
|
if (coordDim == null) {
|
|
resultItem.coordDim = genName(extra, coordDimNameMap, fromZero);
|
|
resultItem.coordDimIndex = 0;
|
|
|
|
if (!generateCoord || generateCoordCount <= 0) {
|
|
resultItem.isExtraCoord = true;
|
|
}
|
|
|
|
generateCoordCount--;
|
|
}
|
|
|
|
resultItem.name == null && (resultItem.name = genName(resultItem.coordDim, dataDimNameMap));
|
|
|
|
if (resultItem.type == null && (guessOrdinal(source, resultDimIdx, resultItem.name) === BE_ORDINAL.Must // Consider the case:
|
|
// {
|
|
// dataset: {source: [
|
|
// ['2001', 123],
|
|
// ['2002', 456],
|
|
// ...
|
|
// ['The others', 987],
|
|
// ]},
|
|
// series: {type: 'pie'}
|
|
// }
|
|
// The first colum should better be treated as a "ordinal" although it
|
|
// might not able to be detected as an "ordinal" by `guessOrdinal`.
|
|
|| resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) {
|
|
resultItem.type = 'ordinal';
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} // ??? TODO
|
|
// Originally detect dimCount by data[0]. Should we
|
|
// optimize it to only by sysDims and dimensions and encode.
|
|
// So only necessary dims will be initialized.
|
|
// But
|
|
// (1) custom series should be considered. where other dims
|
|
// may be visited.
|
|
// (2) sometimes user need to calcualte bubble size or use visualMap
|
|
// on other dimensions besides coordSys needed.
|
|
// So, dims that is not used by system, should be shared in storage?
|
|
|
|
|
|
function getDimCount(source, sysDims, dimsDef, optDimCount) {
|
|
// Note that the result dimCount should not small than columns count
|
|
// of data, otherwise `dataDimNameMap` checking will be incorrect.
|
|
var dimCount = Math.max(source.dimensionsDetectCount || 1, sysDims.length, dimsDef.length, optDimCount || 0);
|
|
each(sysDims, function (sysDimItem) {
|
|
var sysDimItemDimsDef = sysDimItem.dimsDef;
|
|
sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));
|
|
});
|
|
return dimCount;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
var _default = completeDimensions;
|
|
module.exports = _default; |