提交 0b971338 编写于 作者: S SHUANG SU

fix:

(1) Enhance dataset default encode guess strategy. Fix #11428, Fix #11419, Fix #11735
(2) Support candlestick in dataset encode guess.
(3) Some refactor of the code arrangement of dataset encode guess and dimension calculation.
上级 02b55aa5
......@@ -25,7 +25,7 @@ export default SeriesModel.extend({
type: 'series.__base_bar__',
getInitialData: function (option, ecModel) {
return createListFromArray(this.getSource(), this);
return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
},
getMarkerPosition: function (value) {
......
......@@ -27,7 +27,7 @@ export default SeriesModel.extend({
dependencies: ['grid', 'polar'],
getInitialData: function (option, ecModel) {
return createListFromArray(this.getSource(), this);
return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
},
brushSelector: 'point',
......
......@@ -18,8 +18,10 @@
*/
import * as echarts from '../../echarts';
import * as zrUtil from 'zrender/src/core/util';
import createListSimply from '../helper/createListSimply';
import {defaultEmphasis} from '../../util/model';
import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper';
var FunnelSeries = echarts.extendSeriesModel({
......@@ -38,7 +40,10 @@ var FunnelSeries = echarts.extendSeriesModel({
},
getInitialData: function (option, ecModel) {
return createListSimply(this, ['value']);
return createListSimply(this, {
coordDimensions: ['value'],
encodeDefaulter: zrUtil.curry(makeSeriesEncodeForNameBased, this)
});
},
_defaultLabelLine: function (option) {
......
......@@ -24,15 +24,17 @@ import {SOURCE_FORMAT_ORIGINAL} from '../../data/helper/sourceType';
import {getDimensionTypeByAxis} from '../../data/helper/dimensionHelper';
import {getDataItemValue} from '../../util/model';
import CoordinateSystem from '../../CoordinateSystem';
import {getCoordSysDefineBySeries} from '../../model/referHelper';
import {getCoordSysInfoBySeries} from '../../model/referHelper';
import Source from '../../data/Source';
import {enableDataStack} from '../../data/helper/dataStackHelper';
import {makeSeriesEncodeForAxisCoordSys} from '../../data/helper/sourceHelper';
/**
* @param {module:echarts/data/Source|Array} source Or raw data.
* @param {module:echarts/model/Series} seriesModel
* @param {Object} [opt]
* @param {string} [opt.generateCoord]
* @param {boolean} [opt.useEncodeDefaulter]
*/
function createListFromArray(source, seriesModel, opt) {
opt = opt || {};
......@@ -44,14 +46,14 @@ function createListFromArray(source, seriesModel, opt) {
var coordSysName = seriesModel.get('coordinateSystem');
var registeredCoordSys = CoordinateSystem.get(coordSysName);
var coordSysDefine = getCoordSysDefineBySeries(seriesModel);
var coordSysInfo = getCoordSysInfoBySeries(seriesModel);
var coordSysDimDefs;
if (coordSysDefine) {
coordSysDimDefs = zrUtil.map(coordSysDefine.coordSysDims, function (dim) {
if (coordSysInfo) {
coordSysDimDefs = zrUtil.map(coordSysInfo.coordSysDims, function (dim) {
var dimInfo = {name: dim};
var axisModel = coordSysDefine.axisMap.get(dim);
var axisModel = coordSysInfo.axisMap.get(dim);
if (axisModel) {
var axisType = axisModel.get('type');
dimInfo.type = getDimensionTypeByAxis(axisType);
......@@ -72,14 +74,17 @@ function createListFromArray(source, seriesModel, opt) {
var dimInfoList = createDimensions(source, {
coordDimensions: coordSysDimDefs,
generateCoord: opt.generateCoord
generateCoord: opt.generateCoord,
encodeDefaulter: opt.useEncodeDefaulter
? zrUtil.curry(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel)
: null
});
var firstCategoryDimIndex;
var hasNameEncode;
coordSysDefine && zrUtil.each(dimInfoList, function (dimInfo, dimIndex) {
coordSysInfo && zrUtil.each(dimInfoList, function (dimInfo, dimIndex) {
var coordDim = dimInfo.coordDim;
var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);
var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim);
if (categoryAxisModel) {
if (firstCategoryDimIndex == null) {
firstCategoryDimIndex = dimIndex;
......
......@@ -21,6 +21,7 @@
import createListSimply from '../helper/createListSimply';
import * as zrUtil from 'zrender/src/core/util';
import {getDimensionTypeByAxis} from '../../data/helper/dimensionHelper';
import {makeSeriesEncodeForAxisCoordSys} from '../../data/helper/sourceHelper';
export var seriesModelMixin = {
......@@ -47,7 +48,7 @@ export var seriesModelMixin = {
var addOrdinal;
// FIXME
// 考虑时间轴
// Consider time axis.
if (xAxisType === 'category') {
option.layout = 'horizontal';
......@@ -95,25 +96,29 @@ export var seriesModelMixin = {
}
var defaultValueDimensions = this.defaultValueDimensions;
var coordDimensions = [{
name: baseAxisDim,
type: getDimensionTypeByAxis(baseAxisType),
ordinalMeta: ordinalMeta,
otherDims: {
tooltip: false,
itemName: 0
},
dimsDef: ['base']
}, {
name: otherAxisDim,
type: getDimensionTypeByAxis(otherAxisType),
dimsDef: defaultValueDimensions.slice()
}];
return createListSimply(
this,
{
coordDimensions: [{
name: baseAxisDim,
type: getDimensionTypeByAxis(baseAxisType),
ordinalMeta: ordinalMeta,
otherDims: {
tooltip: false,
itemName: 0
},
dimsDef: ['base']
}, {
name: otherAxisDim,
type: getDimensionTypeByAxis(otherAxisType),
dimsDef: defaultValueDimensions.slice()
}],
dimensionsCount: defaultValueDimensions.length + 1
coordDimensions: coordDimensions,
dimensionsCount: defaultValueDimensions.length + 1,
encodeDefaulter: zrUtil.curry(
makeSeriesEncodeForAxisCoordSys, coordDimensions, this
)
}
);
},
......
......@@ -34,7 +34,7 @@ export default SeriesModel.extend({
throw new Error('Line not support coordinateSystem besides cartesian and polar');
}
}
return createListFromArray(this.getSource(), this);
return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
},
defaultOption: {
......
......@@ -24,6 +24,7 @@ import {encodeHTML, addCommas} from '../../util/format';
import dataSelectableMixin from '../../component/helper/selectableMixin';
import {retrieveRawAttr} from '../../data/helper/dataProvider';
import geoSourceManager from '../../coord/geo/geoSourceManager';
import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper';
var MapSeries = SeriesModel.extend({
......@@ -46,7 +47,10 @@ var MapSeries = SeriesModel.extend({
seriesGroup: [],
getInitialData: function (option) {
var data = createListSimply(this, ['value']);
var data = createListSimply(this, {
coordDimensions: ['value'],
encodeDefaulter: zrUtil.curry(makeSeriesEncodeForNameBased, this)
});
var valueDim = data.mapDimension('value');
var dataNameMap = zrUtil.createHashMap();
var selectTargetList = [];
......
......@@ -24,6 +24,7 @@ import * as modelUtil from '../../util/model';
import {getPercentWithPrecision} from '../../util/number';
import dataSelectableMixin from '../../component/helper/selectableMixin';
import {retrieveRawAttr} from '../../data/helper/dataProvider';
import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper';
var PieSeries = echarts.extendSeriesModel({
......@@ -53,7 +54,10 @@ var PieSeries = echarts.extendSeriesModel({
},
getInitialData: function (option, ecModel) {
return createListSimply(this, ['value']);
return createListSimply(this, {
coordDimensions: ['value'],
encodeDefaulter: zrUtil.curry(makeSeriesEncodeForNameBased, this)
});
},
_createSelectableList: function () {
......
......@@ -27,7 +27,7 @@ export default SeriesModel.extend({
dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],
getInitialData: function (option, ecModel) {
return createListFromArray(this.getSource(), this);
return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
},
brushSelector: 'point',
......
/*
* 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 zrUtil from 'zrender/src/core/util';
/**
* @class
* @param {Object|DataDimensionInfo} [opt] All of the fields will be shallow copied.
*/
function DataDimensionInfo(opt) {
if (opt != null) {
zrUtil.extend(this, opt);
}
/**
* Dimension name.
* Mandatory.
* @type {string}
*/
// this.name;
/**
* The origin name in dimsDef, see source helper.
* If displayName given, the tooltip will displayed vertically.
* Optional.
* @type {string}
*/
// this.displayName;
/**
* Which coordSys dimension this dimension mapped to.
* A `coordDim` can be a "coordSysDim" that the coordSys required
* (for example, an item in `coordSysDims` of `model/referHelper#CoordSysInfo`),
* or an generated "extra coord name" if does not mapped to any "coordSysDim"
* (That is determined by whether `isExtraCoord` is `true`).
* Mandatory.
* @type {string}
*/
// this.coordDim;
/**
* The index of this dimension in `series.encode[coordDim]`.
* Mandatory.
* @type {number}
*/
// this.coordDimIndex;
/**
* Dimension type. The enumerable values are the key of
* `dataCtors` of `data/List`.
* Optional.
* @type {string}
*/
// this.type;
/**
* This index of this dimension info in `data/List#_dimensionInfos`.
* Mandatory after added to `data/List`.
* @type {number}
*/
// this.index;
/**
* The format of `otherDims` is:
* ```js
* {
* tooltip: number optional,
* label: number optional,
* itemName: number optional,
* seriesName: number optional,
* }
* ```
*
* A `series.encode` can specified these fields:
* ```js
* encode: {
* // "3, 1, 5" is the index of data dimension.
* tooltip: [3, 1, 5],
* label: [0, 3],
* ...
* }
* ```
* `otherDims` is the parse result of the `series.encode` above, like:
* ```js
* // Suppose the index of this data dimension is `3`.
* this.otherDims = {
* // `3` is at the index `0` of the `encode.tooltip`
* tooltip: 0,
* // `3` is at the index `1` of the `encode.tooltip`
* label: 1
* };
* ```
*
* This prop should never be `null`/`undefined` after initialized.
* @type {Object}
*/
this.otherDims = {};
/**
* Be `true` if this dimension is not mapped to any "coordSysDim" that the
* "coordSys" required.
* Mandatory.
* @type {boolean}
*/
// this.isExtraCoord;
/**
* @type {module:data/OrdinalMeta}
*/
// this.ordinalMeta;
/**
* Whether to create inverted indices.
* @type {boolean}
*/
// this.createInvertedIndices;
};
export default DataDimensionInfo;
......@@ -31,6 +31,7 @@ import DataDiffer from './DataDiffer';
import Source from './Source';
import {defaultDimValueGetters, DefaultDataProvider} from './helper/dataProvider';
import {summarizeDimensions} from './helper/dimensionHelper';
import DataDimensionInfo from './DataDimensionInfo';
var isObject = zrUtil.isObject;
......@@ -102,13 +103,9 @@ function transferProperties(target, source) {
* @constructor
* @alias module:echarts/data/List
*
* @param {Array.<string|Object>} dimensions
* @param {Array.<string|Object|module:data/DataDimensionInfo>} dimensions
* For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].
* Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
* Spetial fields: {
* ordinalMeta: <module:echarts/data/OrdinalMeta>
* createInvertedIndices: <boolean>
* }
* @param {module:echarts/model/Model} hostModel
*/
var List = function (dimensions, hostModel) {
......@@ -124,7 +121,10 @@ var List = function (dimensions, hostModel) {
var dimensionInfo = dimensions[i];
if (zrUtil.isString(dimensionInfo)) {
dimensionInfo = {name: dimensionInfo};
dimensionInfo = new DataDimensionInfo({name: dimensionInfo});
}
else if (!(dimensionInfo instanceof DataDimensionInfo)) {
dimensionInfo = new DataDimensionInfo(dimensionInfo);
}
var dimensionName = dimensionInfo.name;
......
......@@ -24,15 +24,20 @@
import {createHashMap, each, isString, defaults, extend, isObject, clone} from 'zrender/src/core/util';
import {normalizeToArray} from '../../util/model';
import {guessOrdinal} from './sourceHelper';
import {guessOrdinal, BE_ORDINAL} from './sourceHelper';
import Source from '../Source';
import {OTHER_DIMENSIONS} from './dimensionHelper';
import DataDimensionInfo from '../DataDimensionInfo';
/**
* @see {module:echarts/test/ut/spec/data/completeDimensions}
*
* Complete the dimensions array, by user defined `dimension` and `encode`,
* and guessing from the data structure.
* 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'.
*
......@@ -48,32 +53,19 @@ import {OTHER_DIMENSIONS} from './dimensionHelper';
* @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 {module:data/Source}
* 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', ...
* 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.
* 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.
* @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.
* @return {Array.<Object>} [{
* name: string mandatory,
* displayName: string, the origin name in dimsDef, see source helper.
* If displayName given, the tooltip will displayed vertically.
* coordDim: string mandatory,
* coordDimIndex: number mandatory,
* type: string optional,
* otherDims: { never null/undefined
* tooltip: number optional,
* label: number optional,
* itemName: number optional,
* seriesName: number optional,
* },
* isExtraCoord: boolean true if coord is generated
* (not specified in encode and not series specified)
* other props ...
* }]
* @return {Array.<module:data/DataDimensionInfo>}
*/
function completeDimensions(sysDims, source, opt) {
if (!Source.isInstance(source)) {
......@@ -83,7 +75,6 @@ function completeDimensions(sysDims, source, opt) {
opt = opt || {};
sysDims = (sysDims || []).slice();
var dimsDef = (opt.dimsDef || []).slice();
var encodeDef = createHashMap(opt.encodeDef);
var dataDimNameMap = createHashMap();
var coordDimNameMap = createHashMap();
// var valueCandidate;
......@@ -97,7 +88,7 @@ function completeDimensions(sysDims, source, opt) {
{}, isObject(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}
);
var userDimName = dimDefItem.name;
var resultItem = result[i] = {otherDims: {}};
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
......@@ -110,6 +101,12 @@ function completeDimensions(sysDims, source, opt) {
dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
}
var encodeDef = opt.encodeDef;
if (!encodeDef && opt.encodeDefaulter) {
encodeDef = opt.encodeDefaulter(source);
}
encodeDef = createHashMap(encodeDef);
// Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
encodeDef.each(function (dataDims, coordDim) {
dataDims = normalizeToArray(dataDims).slice();
......@@ -211,7 +208,7 @@ function completeDimensions(sysDims, source, opt) {
// Set dim `name` and other `coordDim` and other props.
for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};
var resultItem = result[resultDimIdx] = result[resultDimIdx] || new DataDimensionInfo();
var coordDim = resultItem.coordDim;
if (coordDim == null) {
......@@ -230,7 +227,28 @@ function completeDimensions(sysDims, source, opt) {
dataDimNameMap
));
if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {
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 traded 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';
}
}
......
......@@ -32,6 +32,7 @@ import completeDimensions from './completeDimensions';
* @param {string} [opt.generateCoordCount]
* @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.
* @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.
* @param {Function} [opt.encodeDefaulter] Make default encode if user not specified.
* @return {Array.<Object>} dimensionsInfo
*/
export default function (source, opt) {
......@@ -40,6 +41,7 @@ export default function (source, opt) {
dimsDef: opt.dimensionsDefine || source.dimensionsDefine,
encodeDef: opt.encodeDefine || source.encodeDefine,
dimCount: opt.dimensionsCount,
encodeDefaulter: opt.encodeDefaulter,
generateCoord: opt.generateCoord,
generateCoordCount: opt.generateCoordCount
});
......
......@@ -19,7 +19,6 @@
import {__DEV__} from '../../config';
import {makeInner, getDataItemValue} from '../../util/model';
import {getCoordSysDefineBySeries} from '../../model/referHelper';
import {
createHashMap,
each,
......@@ -44,6 +43,12 @@ import {
SERIES_LAYOUT_BY_ROW
} from './sourceType';
// The result of `guessOrdinal`.
export var BE_ORDINAL = {
Must: 1, // Encounter string but not '-' and not number-like.
Might: 2, // Encounter string but number-like.
Not: 3 // Other cases
};
var inner = makeInner();
......@@ -178,14 +183,6 @@ export function prepareSource(seriesModel) {
data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine
);
// Note: dataset option does not have `encode`.
var encodeDefine = seriesOption.encode;
if (!encodeDefine && datasetModel) {
encodeDefine = makeDefaultEncode(
seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult
);
}
inner(seriesModel).source = new Source({
data: data,
fromDataset: fromDataset,
......@@ -194,7 +191,8 @@ export function prepareSource(seriesModel) {
dimensionsDefine: completeResult.dimensionsDefine,
startIndex: completeResult.startIndex,
dimensionsDetectCount: completeResult.dimensionsDetectCount,
encodeDefine: encodeDefine
// Note: dataset option does not have `encode`.
encodeDefine: seriesOption.encode
});
}
......@@ -206,7 +204,6 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
var dimensionsDetectCount;
var startIndex;
var findPotentialName;
if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
// Rule: Most of the first line are string: it is header.
......@@ -249,13 +246,11 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
if (!dimensionsDefine) {
dimensionsDefine = objectRowsCollectDimensions(data);
findPotentialName = true;
}
}
else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
if (!dimensionsDefine) {
dimensionsDefine = [];
findPotentialName = true;
each(data, function (colArr, key) {
dimensionsDefine.push(key);
});
......@@ -271,21 +266,10 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
}
}
var potentialNameDimIndex;
if (findPotentialName) {
each(dimensionsDefine, function (dim, idx) {
if ((isObject(dim) ? dim.name : dim) === 'name') {
potentialNameDimIndex = idx;
}
});
}
return {
startIndex: startIndex,
dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),
dimensionsDetectCount: dimensionsDetectCount,
potentialNameDimIndex: potentialNameDimIndex
// TODO: potentialIdDimIdx
dimensionsDetectCount: dimensionsDetectCount
};
}
......@@ -359,101 +343,159 @@ function objectRowsCollectDimensions(data) {
}
}
// ??? TODO merge to completedimensions, where also has
// default encode making logic. And the default rule
// should depends on series? consider 'map'.
function makeDefaultEncode(
seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult
) {
var coordSysDefine = getCoordSysDefineBySeries(seriesModel);
/**
* [The strategy of the arrengment of data dimensions for dataset]:
* "value way": all axes are non-category axes. So series one by one take
* several (the number is coordSysDims.length) dimensions from dataset.
* The result of data arrengment of data dimensions like:
* | ser0_x | ser0_y | ser1_x | ser1_y | ser2_x | ser2_y |
* "category way": at least one axis is category axis. So the the first data
* dimension is always mapped to the first category axis and shared by
* all of the series. The other data dimensions are taken by series like
* "value way" does.
* The result of data arrengment of data dimensions like:
* | ser_shared_x | ser0_y | ser1_y | ser2_y |
*
* @param {Array.<Object|string>} coordDimensions [{name: <string>, type: <string>, dimsDef: <Array>}, ...]
* @param {module:model/Series} seriesModel
* @param {module:data/Source} source
* @return {Object} encode Never be `null/undefined`.
*/
export function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) {
var encode = {};
// var encodeTooltip = [];
// var encodeLabel = [];
var datasetModel = getDatasetModel(seriesModel);
// Currently only make default when using dataset, util more reqirements occur.
if (!datasetModel || !coordDimensions) {
return encode;
}
var encodeItemName = [];
var encodeSeriesName = [];
var seriesType = seriesModel.subType;
// ??? TODO refactor: provide by series itself.
// Consider the case: 'map' series is based on geo coordSys,
// 'graph', 'heatmap' can be based on cartesian. But can not
// give default rule simply here.
var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);
var cSeriesMap = createHashMap([
'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'
]);
// Usually in this case series will use the first data
// dimension as the "value" dimension, or other default
// processes respectively.
if (coordSysDefine && cSeriesMap.get(seriesType) != null) {
var ecModel = seriesModel.ecModel;
var datasetMap = inner(ecModel).datasetMap;
var key = datasetModel.uid + '_' + seriesLayoutBy;
var datasetRecord = datasetMap.get(key)
|| datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});
// TODO
// Auto detect first time axis and do arrangement.
each(coordSysDefine.coordSysDims, function (coordDim) {
// In value way.
if (coordSysDefine.firstCategoryDimIndex == null) {
var dataDim = datasetRecord.valueWayDim++;
encode[coordDim] = dataDim;
// ??? TODO give a better default series name rule?
// especially when encode x y specified.
// consider: when mutiple series share one dimension
// category axis, series name should better use
// the other dimsion name. On the other hand, use
// both dimensions name.
encodeSeriesName.push(dataDim);
// encodeTooltip.push(dataDim);
// encodeLabel.push(dataDim);
}
// In category way, category axis.
else if (coordSysDefine.categoryAxisMap.get(coordDim)) {
encode[coordDim] = 0;
encodeItemName.push(0);
}
// In category way, non-category axis.
else {
var dataDim = datasetRecord.categoryWayDim++;
encode[coordDim] = dataDim;
// encodeTooltip.push(dataDim);
// encodeLabel.push(dataDim);
encodeSeriesName.push(dataDim);
var ecModel = seriesModel.ecModel;
var datasetMap = inner(ecModel).datasetMap;
var key = datasetModel.uid + '_' + source.seriesLayoutBy;
var baseCategoryDimIndex;
var categoryWayValueDimStart;
coordDimensions = coordDimensions.slice();
each(coordDimensions, function (coordDimInfo, coordDimIdx) {
!isObject(coordDimInfo) && (coordDimensions[coordDimIdx] = {name: coordDimInfo});
if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) {
baseCategoryDimIndex = coordDimIdx;
categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimensions[coordDimIdx]);
}
encode[coordDimInfo.name] = [];
});
var datasetRecord = datasetMap.get(key)
|| datasetMap.set(key, {categoryWayDim: categoryWayValueDimStart, valueWayDim: 0});
// TODO
// Auto detect first time axis and do arrangement.
each(coordDimensions, function (coordDimInfo, coordDimIdx) {
var coordDimName = coordDimInfo.name;
var count = getDataDimCountOnCoordDim(coordDimInfo);
// In value way.
if (baseCategoryDimIndex == null) {
var start = datasetRecord.valueWayDim;
pushDim(encode[coordDimName], start, count);
pushDim(encodeSeriesName, start, count);
datasetRecord.valueWayDim += count;
// ??? TODO give a better default series name rule?
// especially when encode x y specified.
// consider: when mutiple series share one dimension
// category axis, series name should better use
// the other dimsion name. On the other hand, use
// both dimensions name.
}
// In category way, the first category axis.
else if (baseCategoryDimIndex === coordDimIdx) {
pushDim(encode[coordDimName], 0, count);
pushDim(encodeItemName, 0, count);
}
// In category way, the other axis.
else {
var start = datasetRecord.categoryWayDim;
pushDim(encode[coordDimName], start, count);
pushDim(encodeSeriesName, start, count);
datasetRecord.categoryWayDim += count;
}
});
function pushDim(dimIdxArr, idxFrom, idxCount) {
for (var i = 0; i < idxCount; i++) {
dimIdxArr.push(idxFrom + i);
}
}
function getDataDimCountOnCoordDim(coordDimInfo) {
var dimsDef = coordDimInfo.dimsDef;
return dimsDef ? dimsDef.length : 1;
}
encodeItemName.length && (encode.itemName = encodeItemName);
encodeSeriesName.length && (encode.seriesName = encodeSeriesName);
return encode;
}
/**
* Work for data like [{name: ..., value: ...}, ...].
*
* @param {module:model/Series} seriesModel
* @param {module:data/Source} source
* @return {Object} encode Never be `null/undefined`.
*/
export function makeSeriesEncodeForNameBased(seriesModel, source) {
var encode = {};
var datasetModel = getDatasetModel(seriesModel);
// Currently only make default when using dataset, util more reqirements occur.
if (!datasetModel) {
return encode;
}
var sourceFormat = source.sourceFormat;
var dimensionsDefine = source.dimensionsDefine;
var potentialNameDimIndex;
if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
each(dimensionsDefine, function (dim, idx) {
if ((isObject(dim) ? dim.name : dim) === 'name') {
potentialNameDimIndex = idx;
}
});
}
var encodeItemName = [];
var encodeSeriesName = [];
// Do not make a complex rule! Hard to code maintain and not necessary.
// ??? TODO refactor: provide by series itself.
// [{name: ..., value: ...}, ...] like:
else if (nSeriesMap.get(seriesType) != null) {
// Find the first not ordinal. (5 is an experience value)
var firstNotOrdinal;
for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {
if (!doGuessOrdinal(
data, sourceFormat, seriesLayoutBy,
completeResult.dimensionsDefine, completeResult.startIndex, i
)) {
firstNotOrdinal = i;
}
}
if (firstNotOrdinal != null) {
encode.value = firstNotOrdinal;
var nameDimIndex = completeResult.potentialNameDimIndex
|| Math.max(firstNotOrdinal - 1, 0);
// By default, label use itemName in charts.
// So we dont set encodeLabel here.
encodeSeriesName.push(nameDimIndex);
encodeItemName.push(nameDimIndex);
// encodeTooltip.push(firstNotOrdinal);
}
// Find the first not ordinal. (5 is an experience value)
var firstNotOrdinal;
var firstMaybeOrdinal;
for (var i = 0; i < 5 && (firstNotOrdinal == null || firstMaybeOrdinal == null); i++) {
doGuessOrdinal(
source.data, source.sourceFormat, source.seriesLayoutBy,
dimensionsDefine, source.startIndex, i
) === BE_ORDINAL.Not
? (firstNotOrdinal = i)
: (firstMaybeOrdinal = i);
}
if (firstNotOrdinal != null) {
encode.value = firstNotOrdinal;
var nameDimIndex = potentialNameDimIndex != null
? potentialNameDimIndex
: firstMaybeOrdinal;
// By default, label use itemName in charts.
// So we dont set encodeLabel here.
encodeSeriesName.push(nameDimIndex);
encodeItemName.push(nameDimIndex);
}
// encodeTooltip.length && (encode.tooltip = encodeTooltip);
// encodeLabel.length && (encode.label = encodeLabel);
encodeItemName.length && (encode.itemName = encodeItemName);
encodeSeriesName.length && (encode.seriesName = encodeSeriesName);
......@@ -483,7 +525,7 @@ function getDatasetModel(seriesModel) {
*
* @param {module:echars/data/Source} source
* @param {number} dimIndex
* @return {boolean} Whether ordinal.
* @return {BE_ORDINAL} guess result.
*/
export function guessOrdinal(source, dimIndex) {
return doGuessOrdinal(
......@@ -497,6 +539,7 @@ export function guessOrdinal(source, dimIndex) {
}
// dimIndex may be overflow source data.
// return {BE_ORDINAL}
function doGuessOrdinal(
data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex
) {
......@@ -505,7 +548,7 @@ function doGuessOrdinal(
var maxLoop = 5;
if (isTypedArray(data)) {
return false;
return BE_ORDINAL.Not;
}
// When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine
......@@ -536,7 +579,7 @@ function doGuessOrdinal(
}
else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
if (!dimName) {
return;
return BE_ORDINAL.Not;
}
for (var i = 0; i < data.length && i < maxLoop; i++) {
var item = data[i];
......@@ -547,11 +590,11 @@ function doGuessOrdinal(
}
else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
if (!dimName) {
return;
return BE_ORDINAL.Not;
}
var sample = data[dimName];
if (!sample || isTypedArray(sample)) {
return false;
return BE_ORDINAL.Not;
}
for (var i = 0; i < sample.length && i < maxLoop; i++) {
if ((result = detectValue(sample[i])) != null) {
......@@ -564,7 +607,7 @@ function doGuessOrdinal(
var item = data[i];
var val = getDataItemValue(item);
if (!isArray(val)) {
return false;
return BE_ORDINAL.Not;
}
if ((result = detectValue(val[dimIndex])) != null) {
return result;
......@@ -573,15 +616,16 @@ function doGuessOrdinal(
}
function detectValue(val) {
var beStr = isString(val);
// Consider usage convenience, '1', '2' will be treated as "number".
// `isFinit('')` get `true`.
if (val != null && isFinite(val) && val !== '') {
return false;
return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not;
}
else if (isString(val) && val !== '-') {
return true;
else if (beStr && val !== '-') {
return BE_ORDINAL.Must;
}
}
return false;
return BE_ORDINAL.Not;
}
......@@ -30,7 +30,8 @@ import {__DEV__} from '../config';
import {createHashMap, retrieve, each} from 'zrender/src/core/util';
/**
* @return {Object} For example:
* @class
* For example:
* {
* coordSysName: 'cartesian2d',
* coordSysDims: ['x', 'y', ...],
......@@ -42,19 +43,41 @@ import {createHashMap, retrieve, each} from 'zrender/src/core/util';
* x: xAxisModel,
* y: undefined
* }),
* // It also indicate that whether there is category axis.
* // The index of the first category axis in `coordSysDims`.
* // `null/undefined` means no category axis exists.
* firstCategoryDimIndex: 1,
* // To replace user specified encode.
* }
*/
export function getCoordSysDefineBySeries(seriesModel) {
function CoordSysInfo(coordSysName) {
/**
* @type {string}
*/
this.coordSysName = coordSysName;
/**
* @type {Array.<string>}
*/
this.coordSysDims = [];
/**
* @type {module:zrender/core/util#HashMap}
*/
this.axisMap = createHashMap();
/**
* @type {module:zrender/core/util#HashMap}
*/
this.categoryAxisMap = createHashMap();
/**
* @type {number}
*/
this.firstCategoryDimIndex = null;
}
/**
* @return {module:model/referHelper#CoordSysInfo}
*/
export function getCoordSysInfoBySeries(seriesModel) {
var coordSysName = seriesModel.get('coordinateSystem');
var result = {
coordSysName: coordSysName,
coordSysDims: [],
axisMap: createHashMap(),
categoryAxisMap: createHashMap()
};
var result = new CoordSysInfo(coordSysName);
var fetch = fetchers[coordSysName];
if (fetch) {
fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);
......@@ -95,7 +118,7 @@ var fetchers = {
}
if (isCategory(yAxisModel)) {
categoryAxisMap.set('y', yAxisModel);
result.firstCategoryDimIndex = 1;
result.firstCategoryDimIndex == null & (result.firstCategoryDimIndex = 1);
}
},
......@@ -141,7 +164,7 @@ var fetchers = {
}
if (isCategory(angleAxisModel)) {
categoryAxisMap.set('angle', angleAxisModel);
result.firstCategoryDimIndex = 1;
result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1);
}
},
......
<!DOCTYPE html>
<!--
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.
-->
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="lib/esl.js"></script>
<script src="lib/config.js"></script>
<script src="lib/jquery.min.js"></script>
<script src="lib/facePrint.js"></script>
<script src="lib/testHelper.js"></script>
<!-- <script src="ut/lib/canteen.js"></script> -->
<link rel="stylesheet" href="lib/reset.css" />
</head>
<body>
<style>
</style>
<div id="main0"></div>
<div id="main1"></div>
<div id="main2"></div>
<div id="main3"></div>
<div id="main4"></div>
<div id="main5"></div>
<div id="main6"></div>
<div id="main7"></div>
<div id="main8"></div>
<div id="main9"></div>
<div id="main10"></div>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['分类', '平均消费金额'],
['a007', 100],
['008', 100],
['123', 100],
['333', 100],
['444', 100],
['Test', 100]
]
},
series: [
{type: 'pie', radius: '50%'}
]
};
var chart = testHelper.create(echarts, 'main0', {
title: [
'6 equal sectors should be rendered with labels'
],
option: option,
height: 200
});
});
</script>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['分类', '平均消费金额'],
// number like
['7', 100],
['008', 100],
['123', 100],
['333', 100],
['444', 100],
['Test', 100]
]
},
series: [
{type: 'pie', radius: '50%'}
]
};
var chart = testHelper.create(echarts, 'main1', {
title: [
'6 equal sectors should be rendered with labels'
],
option: option,
height: 200
});
});
</script>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['分类', '平均消费金额'],
// [value, label]
[100, '7'],
[90, '008'],
[80, '123'],
[70, '333'],
[60, '444'],
[50, 'Test']
]
},
series: [
{type: 'funnel', radius: '50%'}
]
};
var chart = testHelper.create(echarts, 'main2', {
title: [
'6 bars (decrease) should be rendered with labels'
],
option: option,
height: 200
});
});
</script>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['分类', 'V100', 'V200', 'V300'],
// number like
['7', 100, 200, 300],
['008', 100, 200, 300],
['123', 100, 200, 300],
['333', 100, 200, 300],
['444', 100, 200, 300],
['Test', 100, 200, 300]
]
},
xAxis: {type: 'category'},
yAxis: {},
series: [
{type: 'bar'},
{type: 'bar'}
]
};
var chart = testHelper.create(echarts, 'main3', {
title: [
'share category xAxis (number-like) and 100, 200 bars'
],
option: option,
height: 200
});
});
</script>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['分类', 'V100', 'V200', 'V300'],
// number like
['7', 100, 200, 300],
['008', 100, 200, 300],
['123', 100, 200, 300],
['333', 100, 200, 300],
['444', 100, 200, 300],
['Test', 100, 200, 300]
]
},
xAxis: {},
yAxis: {},
series: [
{type: 'scatter'},
{type: 'scatter'}
]
};
var chart = testHelper.create(echarts, 'main4', {
title: [
'both x y value axis. Should be series0: "分类 V100", series1: "V200 V300" '
],
option: option,
height: 200
});
});
</script>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['分类', 'O', 'C', 'L', 'H', 'Column'],
['7', 190, 250, 50, 490, 500],
['008', 180, 240, 60, 480, 510],
['123', 170, 230, 70, 470, 520],
['333', 160, 220, 80, 460, 530],
['444', 150, 210, 90, 450, 540],
['Test', 140, 200, 100, 440, 550]
]
},
xAxis: {type: 'category'},
yAxis: {},
series: [
{type: 'candlestick'},
{type: 'line'},
]
};
var chart = testHelper.create(echarts, 'main5', {
title: [
'candlestick series should be "O C L H"',
'line series should be "Column"'
],
option: option,
height: 300
});
});
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册