You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
11 KiB
299 lines
11 KiB
1 month ago
|
|
||
|
/*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||
|
* or more contributor license agreements. See the NOTICE file
|
||
|
* distributed with this work for additional information
|
||
|
* regarding copyright ownership. The ASF licenses this file
|
||
|
* to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance
|
||
|
* with the License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing,
|
||
|
* software distributed under the License is distributed on an
|
||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
* KIND, either express or implied. See the License for the
|
||
|
* specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||
|
* or more contributor license agreements. See the NOTICE file
|
||
|
* distributed with this work for additional information
|
||
|
* regarding copyright ownership. The ASF licenses this file
|
||
|
* to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance
|
||
|
* with the License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing,
|
||
|
* software distributed under the License is distributed on an
|
||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
* KIND, either express or implied. See the License for the
|
||
|
* specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*/
|
||
|
import { isTypedArray, clone, createHashMap, isArray, isObject, isArrayLike, hasOwn, assert, each, map, isNumber, isString, keys } from 'zrender/lib/core/util.js';
|
||
|
import { SOURCE_FORMAT_ORIGINAL, SERIES_LAYOUT_BY_COLUMN, SOURCE_FORMAT_UNKNOWN, SOURCE_FORMAT_KEYED_COLUMNS, SOURCE_FORMAT_TYPED_ARRAY, SOURCE_FORMAT_ARRAY_ROWS, SOURCE_FORMAT_OBJECT_ROWS, SERIES_LAYOUT_BY_ROW } from '../util/types.js';
|
||
|
import { getDataItemValue } from '../util/model.js';
|
||
|
import { BE_ORDINAL, guessOrdinal } from './helper/sourceHelper.js';
|
||
|
;
|
||
|
// @inner
|
||
|
var SourceImpl = /** @class */function () {
|
||
|
function SourceImpl(fields) {
|
||
|
this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []);
|
||
|
this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;
|
||
|
// Visit config
|
||
|
this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;
|
||
|
this.startIndex = fields.startIndex || 0;
|
||
|
this.dimensionsDetectedCount = fields.dimensionsDetectedCount;
|
||
|
this.metaRawOption = fields.metaRawOption;
|
||
|
var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine;
|
||
|
if (dimensionsDefine) {
|
||
|
for (var i = 0; i < dimensionsDefine.length; i++) {
|
||
|
var dim = dimensionsDefine[i];
|
||
|
if (dim.type == null) {
|
||
|
if (guessOrdinal(this, i) === BE_ORDINAL.Must) {
|
||
|
dim.type = 'ordinal';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return SourceImpl;
|
||
|
}();
|
||
|
export function isSourceInstance(val) {
|
||
|
return val instanceof SourceImpl;
|
||
|
}
|
||
|
/**
|
||
|
* Create a source from option.
|
||
|
* NOTE: Created source is immutable. Don't change any properties in it.
|
||
|
*/
|
||
|
export function createSource(sourceData, thisMetaRawOption,
|
||
|
// can be null. If not provided, auto detect it from `sourceData`.
|
||
|
sourceFormat) {
|
||
|
sourceFormat = sourceFormat || detectSourceFormat(sourceData);
|
||
|
var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy;
|
||
|
var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions);
|
||
|
var source = new SourceImpl({
|
||
|
data: sourceData,
|
||
|
sourceFormat: sourceFormat,
|
||
|
seriesLayoutBy: seriesLayoutBy,
|
||
|
dimensionsDefine: determined.dimensionsDefine,
|
||
|
startIndex: determined.startIndex,
|
||
|
dimensionsDetectedCount: determined.dimensionsDetectedCount,
|
||
|
metaRawOption: clone(thisMetaRawOption)
|
||
|
});
|
||
|
return source;
|
||
|
}
|
||
|
/**
|
||
|
* Wrap original series data for some compatibility cases.
|
||
|
*/
|
||
|
export function createSourceFromSeriesDataOption(data) {
|
||
|
return new SourceImpl({
|
||
|
data: data,
|
||
|
sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Clone source but excludes source data.
|
||
|
*/
|
||
|
export function cloneSourceShallow(source) {
|
||
|
return new SourceImpl({
|
||
|
data: source.data,
|
||
|
sourceFormat: source.sourceFormat,
|
||
|
seriesLayoutBy: source.seriesLayoutBy,
|
||
|
dimensionsDefine: clone(source.dimensionsDefine),
|
||
|
startIndex: source.startIndex,
|
||
|
dimensionsDetectedCount: source.dimensionsDetectedCount
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`.
|
||
|
*/
|
||
|
export function detectSourceFormat(data) {
|
||
|
var sourceFormat = SOURCE_FORMAT_UNKNOWN;
|
||
|
if (isTypedArray(data)) {
|
||
|
sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;
|
||
|
} else if (isArray(data)) {
|
||
|
// FIXME Whether tolerate null in top level array?
|
||
|
if (data.length === 0) {
|
||
|
sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
|
||
|
}
|
||
|
for (var i = 0, len = data.length; i < len; i++) {
|
||
|
var item = data[i];
|
||
|
if (item == null) {
|
||
|
continue;
|
||
|
} else if (isArray(item) || isTypedArray(item)) {
|
||
|
sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
|
||
|
break;
|
||
|
} else if (isObject(item)) {
|
||
|
sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else if (isObject(data)) {
|
||
|
for (var key in data) {
|
||
|
if (hasOwn(data, key) && isArrayLike(data[key])) {
|
||
|
sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return sourceFormat;
|
||
|
}
|
||
|
/**
|
||
|
* Determine the source definitions from data standalone dimensions definitions
|
||
|
* are not specified.
|
||
|
*/
|
||
|
function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader,
|
||
|
// standalone raw dimensions definition, like:
|
||
|
// {
|
||
|
// dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }]
|
||
|
// }
|
||
|
// in `dataset` or `series`
|
||
|
dimensionsDefine) {
|
||
|
var dimensionsDetectedCount;
|
||
|
var startIndex;
|
||
|
// PENDING: Could data be null/undefined here?
|
||
|
// currently, if `dataset.source` not specified, error thrown.
|
||
|
// if `series.data` not specified, nothing rendered without error thrown.
|
||
|
// Should test these cases.
|
||
|
if (!data) {
|
||
|
return {
|
||
|
dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
|
||
|
startIndex: startIndex,
|
||
|
dimensionsDetectedCount: dimensionsDetectedCount
|
||
|
};
|
||
|
}
|
||
|
if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
|
||
|
var dataArrayRows = data;
|
||
|
// Rule: Most of the first line are string: it is header.
|
||
|
// Caution: consider a line with 5 string and 1 number,
|
||
|
// it still can not be sure it is a head, because the
|
||
|
// 5 string may be 5 values of category columns.
|
||
|
if (sourceHeader === 'auto' || sourceHeader == null) {
|
||
|
arrayRowsTravelFirst(function (val) {
|
||
|
// '-' is regarded as null/undefined.
|
||
|
if (val != null && val !== '-') {
|
||
|
if (isString(val)) {
|
||
|
startIndex == null && (startIndex = 1);
|
||
|
} else {
|
||
|
startIndex = 0;
|
||
|
}
|
||
|
}
|
||
|
// 10 is an experience number, avoid long loop.
|
||
|
}, seriesLayoutBy, dataArrayRows, 10);
|
||
|
} else {
|
||
|
startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0;
|
||
|
}
|
||
|
if (!dimensionsDefine && startIndex === 1) {
|
||
|
dimensionsDefine = [];
|
||
|
arrayRowsTravelFirst(function (val, index) {
|
||
|
dimensionsDefine[index] = val != null ? val + '' : '';
|
||
|
}, seriesLayoutBy, dataArrayRows, Infinity);
|
||
|
}
|
||
|
dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null;
|
||
|
} else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
|
||
|
if (!dimensionsDefine) {
|
||
|
dimensionsDefine = objectRowsCollectDimensions(data);
|
||
|
}
|
||
|
} else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
|
||
|
if (!dimensionsDefine) {
|
||
|
dimensionsDefine = [];
|
||
|
each(data, function (colArr, key) {
|
||
|
dimensionsDefine.push(key);
|
||
|
});
|
||
|
}
|
||
|
} else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
|
||
|
var value0 = getDataItemValue(data[0]);
|
||
|
dimensionsDetectedCount = isArray(value0) && value0.length || 1;
|
||
|
} else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
|
||
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
startIndex: startIndex,
|
||
|
dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
|
||
|
dimensionsDetectedCount: dimensionsDetectedCount
|
||
|
};
|
||
|
}
|
||
|
function objectRowsCollectDimensions(data) {
|
||
|
var firstIndex = 0;
|
||
|
var obj;
|
||
|
while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line
|
||
|
if (obj) {
|
||
|
return keys(obj);
|
||
|
}
|
||
|
}
|
||
|
// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],
|
||
|
// which is reasonable. But dimension name is duplicated.
|
||
|
// Returns undefined or an array contains only object without null/undefined or string.
|
||
|
function normalizeDimensionsOption(dimensionsDefine) {
|
||
|
if (!dimensionsDefine) {
|
||
|
// The meaning of null/undefined is different from empty array.
|
||
|
return;
|
||
|
}
|
||
|
var nameMap = createHashMap();
|
||
|
return map(dimensionsDefine, function (rawItem, index) {
|
||
|
rawItem = isObject(rawItem) ? rawItem : {
|
||
|
name: rawItem
|
||
|
};
|
||
|
// Other fields will be discarded.
|
||
|
var item = {
|
||
|
name: rawItem.name,
|
||
|
displayName: rawItem.displayName,
|
||
|
type: rawItem.type
|
||
|
};
|
||
|
// User can set null in dimensions.
|
||
|
// We don't auto specify name, otherwise a given name may
|
||
|
// cause it to be referred unexpectedly.
|
||
|
if (item.name == null) {
|
||
|
return item;
|
||
|
}
|
||
|
// Also consider number form like 2012.
|
||
|
item.name += '';
|
||
|
// User may also specify displayName.
|
||
|
// displayName will always exists except user not
|
||
|
// specified or dim name is not specified or detected.
|
||
|
// (A auto generated dim name will not be used as
|
||
|
// displayName).
|
||
|
if (item.displayName == null) {
|
||
|
item.displayName = item.name;
|
||
|
}
|
||
|
var exist = nameMap.get(item.name);
|
||
|
if (!exist) {
|
||
|
nameMap.set(item.name, {
|
||
|
count: 1
|
||
|
});
|
||
|
} else {
|
||
|
item.name += '-' + exist.count++;
|
||
|
}
|
||
|
return item;
|
||
|
});
|
||
|
}
|
||
|
function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {
|
||
|
if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
|
||
|
for (var i = 0; i < data.length && i < maxLoop; i++) {
|
||
|
cb(data[i] ? data[i][0] : null, i);
|
||
|
}
|
||
|
} else {
|
||
|
var value0 = data[0] || [];
|
||
|
for (var i = 0; i < value0.length && i < maxLoop; i++) {
|
||
|
cb(value0[i], i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
export function shouldRetrieveDataByName(source) {
|
||
|
var sourceFormat = source.sourceFormat;
|
||
|
return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS;
|
||
|
}
|