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.
329 lines
11 KiB
329 lines
11 KiB
|
|
/* |
|
* 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)) { |
|
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; |
|
} |