/*
|
* 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.
|
*/
|
|
// TODO
|
// ??? refactor? check the outer usage of data provider.
|
// merge with defaultDimValueGetter?
|
|
import {__DEV__} from '../../config';
|
import {isTypedArray, extend, assert, each, isObject} from 'zrender/src/core/util';
|
import {getDataItemValue, isDataItemOption} from '../../util/model';
|
import {parseDate} from '../../util/number';
|
import Source from '../Source';
|
import {
|
SOURCE_FORMAT_TYPED_ARRAY,
|
SOURCE_FORMAT_ARRAY_ROWS,
|
SOURCE_FORMAT_ORIGINAL,
|
SOURCE_FORMAT_OBJECT_ROWS
|
} from './sourceType';
|
|
/**
|
* If normal array used, mutable chunk size is supported.
|
* If typed array used, chunk size must be fixed.
|
*/
|
export function DefaultDataProvider(source, dimSize) {
|
if (!Source.isInstance(source)) {
|
source = Source.seriesDataToSource(source);
|
}
|
this._source = source;
|
|
var data = this._data = source.data;
|
var sourceFormat = source.sourceFormat;
|
|
// Typed array. TODO IE10+?
|
if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
|
if (__DEV__) {
|
if (dimSize == null) {
|
throw new Error('Typed array data must specify dimension size');
|
}
|
}
|
this._offset = 0;
|
this._dimSize = dimSize;
|
this._data = data;
|
}
|
|
var methods = providerMethods[
|
sourceFormat === SOURCE_FORMAT_ARRAY_ROWS
|
? sourceFormat + '_' + source.seriesLayoutBy
|
: sourceFormat
|
];
|
|
if (__DEV__) {
|
assert(methods, 'Invalide sourceFormat: ' + sourceFormat);
|
}
|
|
extend(this, methods);
|
}
|
|
var providerProto = DefaultDataProvider.prototype;
|
// If data is pure without style configuration
|
providerProto.pure = false;
|
// If data is persistent and will not be released after use.
|
providerProto.persistent = true;
|
|
// ???! FIXME legacy data provider do not has method getSource
|
providerProto.getSource = function () {
|
return this._source;
|
};
|
|
var providerMethods = {
|
|
'arrayRows_column': {
|
pure: true,
|
count: function () {
|
return Math.max(0, this._data.length - this._source.startIndex);
|
},
|
getItem: function (idx) {
|
return this._data[idx + this._source.startIndex];
|
},
|
appendData: appendDataSimply
|
},
|
|
'arrayRows_row': {
|
pure: true,
|
count: function () {
|
var row = this._data[0];
|
return row ? Math.max(0, row.length - this._source.startIndex) : 0;
|
},
|
getItem: function (idx) {
|
idx += this._source.startIndex;
|
var item = [];
|
var data = this._data;
|
for (var i = 0; i < data.length; i++) {
|
var row = data[i];
|
item.push(row ? row[idx] : null);
|
}
|
return item;
|
},
|
appendData: function () {
|
throw new Error('Do not support appendData when set seriesLayoutBy: "row".');
|
}
|
},
|
|
'objectRows': {
|
pure: true,
|
count: countSimply,
|
getItem: getItemSimply,
|
appendData: appendDataSimply
|
},
|
|
'keyedColumns': {
|
pure: true,
|
count: function () {
|
var dimName = this._source.dimensionsDefine[0].name;
|
var col = this._data[dimName];
|
return col ? col.length : 0;
|
},
|
getItem: function (idx) {
|
var item = [];
|
var dims = this._source.dimensionsDefine;
|
for (var i = 0; i < dims.length; i++) {
|
var col = this._data[dims[i].name];
|
item.push(col ? col[idx] : null);
|
}
|
return item;
|
},
|
appendData: function (newData) {
|
var data = this._data;
|
each(newData, function (newCol, key) {
|
var oldCol = data[key] || (data[key] = []);
|
for (var i = 0; i < (newCol || []).length; i++) {
|
oldCol.push(newCol[i]);
|
}
|
});
|
}
|
},
|
|
'original': {
|
count: countSimply,
|
getItem: getItemSimply,
|
appendData: appendDataSimply
|
},
|
|
'typedArray': {
|
persistent: false,
|
pure: true,
|
count: function () {
|
return this._data ? (this._data.length / this._dimSize) : 0;
|
},
|
getItem: function (idx, out) {
|
idx = idx - this._offset;
|
out = out || [];
|
var offset = this._dimSize * idx;
|
for (var i = 0; i < this._dimSize; i++) {
|
out[i] = this._data[offset + i];
|
}
|
return out;
|
},
|
appendData: function (newData) {
|
if (__DEV__) {
|
assert(
|
isTypedArray(newData),
|
'Added data must be TypedArray if data in initialization is TypedArray'
|
);
|
}
|
|
this._data = newData;
|
},
|
|
// Clean self if data is already used.
|
clean: function () {
|
// PENDING
|
this._offset += this.count();
|
this._data = null;
|
}
|
}
|
};
|
|
function countSimply() {
|
return this._data.length;
|
}
|
function getItemSimply(idx) {
|
return this._data[idx];
|
}
|
function appendDataSimply(newData) {
|
for (var i = 0; i < newData.length; i++) {
|
this._data.push(newData[i]);
|
}
|
}
|
|
|
|
var rawValueGetters = {
|
|
arrayRows: getRawValueSimply,
|
|
objectRows: function (dataItem, dataIndex, dimIndex, dimName) {
|
return dimIndex != null ? dataItem[dimName] : dataItem;
|
},
|
|
keyedColumns: getRawValueSimply,
|
|
original: function (dataItem, dataIndex, dimIndex, dimName) {
|
// FIXME
|
// In some case (markpoint in geo (geo-map.html)), dataItem
|
// is {coord: [...]}
|
var value = getDataItemValue(dataItem);
|
return (dimIndex == null || !(value instanceof Array))
|
? value
|
: value[dimIndex];
|
},
|
|
typedArray: getRawValueSimply
|
};
|
|
function getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {
|
return dimIndex != null ? dataItem[dimIndex] : dataItem;
|
}
|
|
|
export var defaultDimValueGetters = {
|
|
arrayRows: getDimValueSimply,
|
|
objectRows: function (dataItem, dimName, dataIndex, dimIndex) {
|
return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);
|
},
|
|
keyedColumns: getDimValueSimply,
|
|
original: function (dataItem, dimName, dataIndex, dimIndex) {
|
// Performance sensitive, do not use modelUtil.getDataItemValue.
|
// If dataItem is an plain object with no value field, the var `value`
|
// will be assigned with the object, but it will be tread correctly
|
// in the `convertDataValue`.
|
var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);
|
|
// If any dataItem is like { value: 10 }
|
if (!this._rawData.pure && isDataItemOption(dataItem)) {
|
this.hasItemOption = true;
|
}
|
return converDataValue(
|
(value instanceof Array)
|
? value[dimIndex]
|
// If value is a single number or something else not array.
|
: value,
|
this._dimensionInfos[dimName]
|
);
|
},
|
|
typedArray: function (dataItem, dimName, dataIndex, dimIndex) {
|
return dataItem[dimIndex];
|
}
|
|
};
|
|
function getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {
|
return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);
|
}
|
|
/**
|
* This helper method convert value in data.
|
* @param {string|number|Date} value
|
* @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.
|
* If "dimInfo.ordinalParseAndSave", ordinal value can be parsed.
|
*/
|
function converDataValue(value, dimInfo) {
|
// Performance sensitive.
|
var dimType = dimInfo && dimInfo.type;
|
if (dimType === 'ordinal') {
|
// If given value is a category string
|
var ordinalMeta = dimInfo && dimInfo.ordinalMeta;
|
return ordinalMeta
|
? ordinalMeta.parseAndCollect(value)
|
: value;
|
}
|
|
if (dimType === 'time'
|
// spead up when using timestamp
|
&& typeof value !== 'number'
|
&& value != null
|
&& value !== '-'
|
) {
|
value = +parseDate(value);
|
}
|
|
// dimType defaults 'number'.
|
// If dimType is not ordinal and value is null or undefined or NaN or '-',
|
// parse to NaN.
|
return (value == null || value === '')
|
? NaN
|
// If string (like '-'), using '+' parse to NaN
|
// If object, also parse to NaN
|
: +value;
|
}
|
|
// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,
|
// Consider persistent.
|
// Caution: why use raw value to display on label or tooltip?
|
// A reason is to avoid format. For example time value we do not know
|
// how to format is expected. More over, if stack is used, calculated
|
// value may be 0.91000000001, which have brings trouble to display.
|
// TODO: consider how to treat null/undefined/NaN when display?
|
/**
|
* @param {module:echarts/data/List} data
|
* @param {number} dataIndex
|
* @param {string|number} [dim] dimName or dimIndex
|
* @return {Array.<number>|string|number} can be null/undefined.
|
*/
|
export function retrieveRawValue(data, dataIndex, dim) {
|
if (!data) {
|
return;
|
}
|
|
// Consider data may be not persistent.
|
var dataItem = data.getRawDataItem(dataIndex);
|
|
if (dataItem == null) {
|
return;
|
}
|
|
var sourceFormat = data.getProvider().getSource().sourceFormat;
|
var dimName;
|
var dimIndex;
|
|
var dimInfo = data.getDimensionInfo(dim);
|
if (dimInfo) {
|
dimName = dimInfo.name;
|
dimIndex = dimInfo.index;
|
}
|
|
return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);
|
}
|
|
/**
|
* Compatible with some cases (in pie, map) like:
|
* data: [{name: 'xx', value: 5, selected: true}, ...]
|
* where only sourceFormat is 'original' and 'objectRows' supported.
|
*
|
* ??? TODO
|
* Supported detail options in data item when using 'arrayRows'.
|
*
|
* @param {module:echarts/data/List} data
|
* @param {number} dataIndex
|
* @param {string} attr like 'selected'
|
*/
|
export function retrieveRawAttr(data, dataIndex, attr) {
|
if (!data) {
|
return;
|
}
|
|
var sourceFormat = data.getProvider().getSource().sourceFormat;
|
|
if (sourceFormat !== SOURCE_FORMAT_ORIGINAL
|
&& sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS
|
) {
|
return;
|
}
|
|
var dataItem = data.getRawDataItem(dataIndex);
|
if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject(dataItem)) {
|
dataItem = null;
|
}
|
if (dataItem) {
|
return dataItem[attr];
|
}
|
}
|