提交 3067fe75 编写于 作者: S sushuang

(1) fix parallel, support encode.

(2) fix category axis collect.
(3) some refactor about source and create list.
上级 7bc1f936
import * as zrUtil from 'zrender/src/core/util';
import List from '../../data/List';
import createDimensions from '../../data/helper/createDimensions';
import {getDimTypeByAxis} from '../../data/helper/sourceHelper';
import {getDataItemValue} from '../../util/model';
import CoordinateSystem from '../../CoordinateSystem';
import {getCoordSysDefineBySeries} from '../../model/referHelper';
/**
* @param {Object} source
* {
* data: mandatory
* encodeDefine: optional
* dimensionsDefine: optional
* }
* @param {module:echarts/data/Source} source
* @param {module:echarts/model/Series} seriesModel
*/
function createListFromArray(source, seriesModel) {
......@@ -57,7 +53,7 @@ function createListFromArray(source, seriesModel) {
var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);
if (categoryAxisModel) {
firstCategoryDimIndex == null && (firstCategoryDimIndex = dimIndex);
categoryAxisModel.ordinalMeta.prepareDimInfo(dimInfo, source);
dimInfo.ordinalMeta = categoryAxisModel.ordinalMeta;
}
});
......@@ -82,14 +78,6 @@ function isStackable(axisType) {
return axisType !== 'category' && axisType !== 'time';
}
function getDimTypeByAxis(axisType) {
return axisType === 'category'
? 'ordinal'
: axisType === 'time'
? 'time'
: 'float';
}
function firstDataNotNull(data) {
var i = 0;
while (i < data.length && data[i] == null) {
......
import List from '../../data/List';
import * as zrUtil from 'zrender/src/core/util';
import {each, createHashMap} from 'zrender/src/core/util';
import SeriesModel from '../../model/Series';
import guessOrdinal from '../../data/helper/guessOrdinal';
import createListFromArray from '../helper/createListFromArray';
export default SeriesModel.extend({
......@@ -12,48 +11,16 @@ export default SeriesModel.extend({
visualColorAccessPath: 'lineStyle.color',
getInitialData: function (option, ecModel) {
var parallelModel = ecModel.getComponent(
'parallel', this.get('parallelIndex')
);
var parallelAxisIndices = parallelModel.parallelAxisIndex;
var source = this.getSource();
var rawData = source.data;
var modelDims = parallelModel.dimensions;
var dataDims = generateDataDims(modelDims, rawData);
// ??? need support encode?
var dataDimsInfo = zrUtil.map(dataDims, function (dim, dimIndex) {
var modelDimsIndex = zrUtil.indexOf(modelDims, dim);
var axisModel = modelDimsIndex >= 0 && ecModel.getComponent(
'parallelAxis', parallelAxisIndices[modelDimsIndex]
);
if (axisModel && axisModel.get('type') === 'category') {
translateCategoryValue(axisModel, dim, rawData);
return {name: dim, type: 'ordinal'};
}
else if (modelDimsIndex < 0) {
return guessOrdinal(rawData, dimIndex)
? {name: dim, type: 'ordinal'}
: dim;
}
else {
return dim;
}
});
var list = new List(dataDimsInfo, this);
list.initData(rawData);
// Anication is forbiden in progressive data mode.
if (this.option.progressive) {
this.option.animation = false;
}
return list;
var source = this.getSource();
setEncodeAndDimensions(source, this);
return createListFromArray(source, this);
},
/**
......@@ -109,50 +76,110 @@ export default SeriesModel.extend({
}
});
function translateCategoryValue(axisModel, dim, rawData) {
var axisData = axisModel.getCategories();
var numberDim = convertDimNameToNumber(dim);
function setEncodeAndDimensions(source, seriesModel) {
// The mapping of parallelAxis dimension to data dimension can
// be specified in parallelAxis.option.dim. For example, if
// parallelAxis.option.dim is 'dim3', it mapping to the third
// dimension of data. But `data.encode` has higher priority.
// Moreover, parallelModel.dimension should not be regarded as data
// dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6'];
if (axisData && axisData.length) {
zrUtil.each(rawData, function (dataItem) {
if (!dataItem) {
return;
}
// FIXME
// time consuming, should use hash?
var index = zrUtil.indexOf(axisData, dataItem[numberDim]);
dataItem[numberDim] = index >= 0 ? index : NaN;
});
if (source.encodeDefine) {
return;
}
var parallelModel = seriesModel.ecModel.getComponent(
'parallel', seriesModel.get('parallelIndex')
);
if (!parallelModel) {
return;
}
// FIXME
// 如果没有设置axis data, 应自动算出,或者提示。
var encodeDefine = source.encodeDefine = createHashMap();
each(parallelModel.dimensions, function (axisDim) {
var dataDimIndex = convertDimNameToNumber(axisDim);
encodeDefine.set(axisDim, dataDimIndex);
});
}
function convertDimNameToNumber(dimName) {
return +dimName.replace('dim', '');
}
function generateDataDims(modelDims, rawData) {
// parallelModel.dimension should not be regarded as data
// dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6'];
// We detect max dim by parallelModel.dimensions and fist
// item in rawData arbitrarily.
var maxDimNum = 0;
zrUtil.each(modelDims, function (dimName) {
var numberDim = convertDimNameToNumber(dimName);
numberDim > maxDimNum && (maxDimNum = numberDim);
});
var firstItem = rawData[0];
if (firstItem && firstItem.length - 1 > maxDimNum) {
maxDimNum = firstItem.length - 1;
}
var dataDims = [];
for (var i = 0; i <= maxDimNum; i++) {
dataDims.push('dim' + i);
}
return dataDims;
}
\ No newline at end of file
// function translateCategoryValue(axisModel, dim, rawData) {
// // ???!!
// var axisData = axisModel.getCategories();
// var numberDim = convertDimNameToNumber(dim);
// if (axisData && axisData.length) {
// zrUtil.each(rawData, function (dataItem) {
// if (!dataItem) {
// return;
// }
// // FIXME
// // time consuming, should use hash?
// var index = zrUtil.indexOf(axisData, dataItem[numberDim]);
// dataItem[numberDim] = index >= 0 ? index : NaN;
// });
// }
// // FIXME
// // 如果没有设置axis data, 应自动算出,或者提示。
// }
// function generateDimParams(parallelModel, source) {
// var parallelAxisIndices = parallelModel.parallelAxisIndex;
// var modelDims = parallelModel.dimensions;
// getDimTypeByAxis
// ??? need support encode?
// var dataDimsInfo = zrUtil.map(dataDims, function (dim, dimIndex) {
// var modelDimsIndex = zrUtil.indexOf(modelDims, dim);
// var axisModel = modelDimsIndex >= 0 && ecModel.getComponent(
// 'parallelAxis', parallelAxisIndices[modelDimsIndex]
// );
// if (axisModel && axisModel.get('type') === 'category') {
// translateCategoryValue(axisModel, dim, source);
// return {name: dim, type: 'ordinal'};
// }
// else if (modelDimsIndex < 0) {
// return guessOrdinal(source, dimIndex)
// ? {name: dim, type: 'ordinal'}
// : dim;
// }
// else {
// return dim;
// }
// });
// TODO
// ??? Do not support encode and dimensions setting in parallels currently.
// encode and dimension are specified by parallelAxis.
// var encodeDefine = {};
// var sysDimensions = {};
// // parallelModel.dimension should not be regarded as data
// // dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6'];
// var maxDimNum = 0;
// each(modelDims, function (dimName) {
// var numberDim = +dimName.replace('dim', '');
// numberDim > maxDimNum && (maxDimNum = numberDim);
// encodeDefine[dimName] = dimName;
// });
// var dataDims = [];
// for (var i = 0; i <= maxDimNum; i++) {
// dataDims.push('dim' + i);
// }
// var params = zrUtil.defaults({
// sysDimensions: modelDims,
// dimensionsDefine: dataDims,
// encodeDefine: encodeDefine
// }, source);
// return params;
// }
import * as echarts from '../../echarts';
import { detectSourceFormat } from '../../data/helper/sourceHelper';
var DatasetModel = echarts.extendComponentModel({
type: 'dataset',
/**
* @readOnly
*/
parsedData: null,
/**
* @protected
*/
defaultOption: {
sourceType: 'rows', // 'rows', 'columns', 'objects'
// 'row', 'column'
seriesLayoutBy: 'column',
// see "module:echarts/data/helper/sourceHelper#detectSourceFormat"
sourceFormat: 'unknown',
header: true,
dimensions: null,
source: null
},
......@@ -16,30 +32,13 @@ var DatasetModel = echarts.extendComponentModel({
* @override
*/
optionUpdated: function () {
parseData(this.option);
var option = this.option;
var sourceFormat = option.sourceFormat;
if (sourceFormat == null || sourceFormat === 'unknown') {
option.sourceFormat = detectSourceFormat(option.source);
}
}
});
function parseData(option) {
var sourceType = option.sourceType;
var parser = parsers[sourceType];
if (parser && option.source) {
option.data = parser(option.source, option);
}
option.source = null;
}
var parsers = {
rows: function (source, option) {
return source;
},
columns: function (source, option) {
// TODO
},
objects: function (source, option) {
// TODO
}
};
export default DatasetModel;
......@@ -101,6 +101,14 @@ var axisDefault = {};
axisDefault.categoryAxis = zrUtil.merge({
// 类目起始和结束两端空白策略
boundaryGap: true,
// Set false to faster category collection.
// Only usefull in the case like: category is
// ['2012-01-01', '2012-01-02', ...], where the input
// data has been ensured not duplicate and is large data.
// null means "auto":
// if axis.data provided, do not deduplication,
// else do deduplication.
deduplication: null,
// splitArea: {
// show: false
// },
......
......@@ -60,7 +60,13 @@ export default function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraD
}
},
/**
* Should not be called before all of 'getInitailData' finished.
* Because categories are collected during initializing data.
*/
getCategories: function () {
// FIXME
// warning if called before all of 'getInitailData' finished.
if (this.option.type === 'category') {
return this.ordinalMeta.categories;
}
......
......@@ -153,8 +153,7 @@ var typedArrayProviderMethods = {
* 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>,
* sourceModelUID: <string>
* ordinalMeta: <module:echarts/data/OrdinalMeta>
* }
* @param {module:echarts/model/Model} hostModel
*/
......@@ -1733,7 +1732,7 @@ function converDataValue(value, dimInfo) {
return !ordinalMeta
? value
: typeof value === 'string'
? ordinalMeta.parseAndCollect(value, dimInfo.sourceModelUID)
? ordinalMeta.parseAndCollect(value)
: NaN;
}
......
......@@ -27,9 +27,9 @@ function OrdinalMeta(axisModel) {
/**
* @private
* @type {string}
* @type {boolean}
*/
this._sourceModelUID = categories ? axisModel.uid : NO_SOURCE;
this._preventDeduplication = axisModel.get('dedplication', true) === false;
/**
* @private
......@@ -50,16 +50,21 @@ proto.getOrdinal = function (category) {
/**
* @param {string} category
* @param {string} [dimSourceModelUID]
* @return {number} The ordinal. If not found, return NaN.
*/
proto.parseAndCollect = function (category, dimSourceModelUID) {
proto.parseAndCollect = function (category) {
var index;
var needCollect = this._needCollect;
// Optimize for the scenario: Only a dataset dimension provide categroies
// and many series use the dimension. We avoid to create map.
if (needCollect && dimSourceModelUID === this._sourceModelUID) {
// Optimize for the scenario:
// category is ['2012-01-01', '2012-01-02', ...], where the input
// data has been ensured not duplicate and is large data.
// Notice, if a dataset dimension provide categroies, usually echarts
// should remove duplication except user tell echarts dont do that
// (set axis.deduplication = false), because echarts do not know whether
// the values in the category dimension has duplication (consider the
// parallel-aqi example)
if (needCollect && this._preventDeduplication) {
index = this.categories.length;
this.categories[index] = category;
return index;
......@@ -82,31 +87,6 @@ proto.parseAndCollect = function (category, dimSourceModelUID) {
return index;
};
proto.prepareDimInfo = function (dimInfo, source) {
dimInfo.ordinalMeta = this;
addSourceModelUID(this, source.modelUID);
dimInfo.sourceModelUID = source.modelUID;
};
/**
* Consider these cases:
* (1) A category axis provides data (categories) and
* many series refer the axis.
* (2) Only a dataset dimension provide categroies and many
* series use the dimension.
*
* In those cases above, categoryMap is not needed to be
* created. So we use sourceModelUID to make this optimization.
* @private
*/
function addSourceModelUID(ordinalMeta, sourceModelUID) {
if (ordinalMeta._needCollect) {
ordinalMeta._sourceModelUID = ordinalMeta._sourceModelUID === NO_SOURCE
? sourceModelUID
: MULTIPLE_SOURCE;
}
}
// Do not create map until needed.
function getOrCreateMap(ordinalMeta) {
return ordinalMeta._map || (
......
import {extend, createHashMap} from 'zrender/src/core/util';
/**
* [sourceFormat]
*
* + "seriesOriginal":
* This format is only used in series.data, where
* itemStyle can be specified in data item.
*
* + "array2d":
* [
* ['product', 'score', 'amount'],
* ['Matcha Latte', 89.3, 95.8],
* ['Milk Tea', 92.1, 89.4],
* ['Cheese Cocoa', 94.4, 91.2],
* ['Walnut Brownie', 85.4, 76.9]
* ]
*
* + "keyValues":
* [
* {product: 'Matcha Latte', score: 89.3, amount: 95.8},
* {product: 'Milk Tea', score: 92.1, amount: 89.4},
* {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},
* {product: 'Walnut Brownie', score: 85.4, amount: 76.9}
* ]
*
* + "keyArrays":
* {
* 'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],
* 'count': [823, 235, 1042, 988],
* 'score': [95.8, 81.4, 91.2, 76.9]
* }
*
* + "typedArray"
*
* + null/undefined
*
*/
/**
* @constructor
* @param {Object} fields
* @param {string} fields.modelUID Not null/undefined.
* @param {Array|Object} fields.data Not null/undefined.
* @param {Array.<Object|string>} dimensionsDefine Original define, can be null/undefined.
* @param {string} seriesLayoutBy 'row' or 'column'
* @param {HashMap} encodeDefine Original define, can be null/undefined.
* @param {string} sourceFormat See also"detectSourceFormat".
*/
function Source(fields) {
extend(this, fields);
if (this.encodeDefine) {
this.encodeDefine = createHashMap(this.encodeDefine);
}
}
export default Source;
\ No newline at end of file
......@@ -6,7 +6,7 @@
import * as zrUtil from 'zrender/src/core/util';
import {normalizeToArray, getDataItemValue} from '../../util/model';
import guessOrdinal from './guessOrdinal';
import {guessOrdinal} from './sourceHelper';
var each = zrUtil.each;
var isString = zrUtil.isString;
......@@ -69,8 +69,11 @@ function completeDimensions(sysDims, data, opt) {
// 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 custom series should be considered. where other dims
// 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.
var value0 = getDataItemValue(data[0]);
dimCount = Math.max(
zrUtil.isArray(value0) && value0.length || 1,
......@@ -173,9 +176,11 @@ function completeDimensions(sysDims, data, opt) {
dataDimNameMap
));
if (!isDataTypedArray) {
resultItem.type == null && guessOrdinal(data, resultDimIdx)
&& (resultItem.type = 'ordinal');
if (!isDataTypedArray
&& resultItem.type == null
&& guessOrdinal(data, resultDimIdx)
) {
resultItem.type = 'ordinal';
}
}
......
import {isArray, isString} from 'zrender/src/core/util';
import {getDataItemValue} from '../../util/model';
// The rule should not be complex, otherwise user might not
// be able to known where the data is wrong.
export default function (data, dimIndex) {
for (var i = 0, len = data.length; i < len; i++) {
var value = getDataItemValue(data[i]);
if (!isArray(value)) {
return false;
}
var value = value[dimIndex];
// Consider usage convenience, '1', '2' will be treated as "number".
// `isFinit('')` get `true`.
if (value != null && isFinite(value) && value !== '') {
return false;
}
else if (isString(value) && value !== '-') {
return true;
}
}
return false;
}
import {makeInner} from '../../util/model';
import {getCoordSysDefineBySeries} from '../../model/referHelper';
import {createHashMap, each} from 'zrender/src/core/util';
import {createHashMap, each, isArray, isString, isObject} from 'zrender/src/core/util';
import {getDataItemValue} from '../../util/model';
import Source from '../Source';
var inner = makeInner();
/**
* [Scenarios]:
* (1) Provide source data directly:
* series: {
* encode: {...},
* dimensions: [...]
* seriesLayoutBy: 'row',
* data: [[...]]
* }
* (2) Refer to datasetModel.
* series: [{
* encode: {...}
* // Ignore datasetIndex means `datasetIndex: 0`
* // and the dimensions defination in dataset is used
* }, {
* encode: {...},
* seriesLayoutBy: 'column',
* datasetIndex: 1
* }]
*
* Get data from series itself or datset.
* @return {module:echarts/data/Source} source
*/
export function getSource(seriesModel) {
var seriesOption = seriesModel.option;
var modelUID = seriesModel.uid;
var data = seriesOption.data;
var dimensionsDefine = seriesOption.dimensions;
var seriesLayoutBy = seriesOption.seriesLayoutBy;
var sourceFormat = 'seriesOriginal';
var datasetModel = getDatasetModel(seriesModel);
if (datasetModel) {
var datasetOption = datasetModel.option;
modelUID = datasetModel.uid;
data = datasetModel.parsedData;
// Dimensions defined on series has higher priority.
dimensionsDefine = dimensionsDefine || detectDatasetDimensions(datasetModel);
seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;
sourceFormat = datasetOption.sourceFormat;
}
return new Source({
modelUID: modelUID,
// Do not clone data for performance.
data: data,
dimensionsDefine: dimensionsDefine ? dimensionsDefine.slice() : null,
seriesLayoutBy: seriesLayoutBy,
encodeDefine: inner(seriesModel).encode,
sourceFormat: sourceFormat
});
}
/**
* MUST be called before mergeOption of all series.
* @param {module:echarts/model/Global} ecModel
*/
export function resetDefaultEncode(ecModel) {
inner(ecModel).datasetMap = createHashMap();
}
......@@ -23,11 +82,21 @@ export function resetDefaultEncode(ecModel) {
* series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],
* where the "y" have to be manually typed as "1, 2, 3, ...".
*
* @return {Object} The object of default encode.
* @param {module:echarts/model/Series} seriesModel
*/
export function makeDefaultEncode(seriesModel) {
var ecModel = seriesModel.ecModel;
var datasetMap = inner(ecModel).datasetMap;
export function setEncode(seriesModel) {
var datasetModel = getDatasetModel(seriesModel);
// Note: dataset option does not have `encode`.
var optionEncode = seriesModel.option.encode;
inner(seriesModel).encode = (!optionEncode && datasetModel)
? makeDefaultEncode(seriesModel, datasetModel)
: optionEncode;
}
function makeDefaultEncode(seriesModel, datasetModel) {
if (!datasetModel) {
return;
}
var coordSysDefine = getCoordSysDefineBySeries(seriesModel);
......@@ -35,16 +104,11 @@ export function makeDefaultEncode(seriesModel) {
// Usually in this case series will use the first data
// dimension as the "value" dimension, or other default
// processes respectively.
// ??? clear default incode
return;
}
var datasetModel = getDatasetModel(seriesModel);
if (!datasetModel) {
return;
}
var ecModel = seriesModel.ecModel;
var datasetMap = inner(ecModel).datasetMap;
var datasetUID = datasetModel.uid;
var datasetRecord = datasetMap.get(datasetUID)
|| datasetMap.set(datasetUID, {categoryWayDim: 1, valueWayDim: 0});
......@@ -64,10 +128,99 @@ export function makeDefaultEncode(seriesModel) {
return encode;
}
export function getDatasetModel(seriesModel) {
var thisData = seriesModel.option.data;
return seriesModel.ecModel.getComponent(
'dataset', thisData && thisData.datasetIndex || 0
);
/**
* If return null/undefined, indicate that should not use datasetModel.
*/
function getDatasetModel(seriesModel) {
var option = seriesModel.option;
// Caution: consider the scenario:
// A dataset is declared and a series is not expected to use the dataset,
// and at the beginning `setOption({series: { noData })` (just prepare other
// option but no data), then `setOption({series: {data: [...]}); In this case,
// the user should set an empty array to avoid that dataset is used by default.
var thisData = option.data;
if (!thisData) {
return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);
}
}
// The rule should not be complex, otherwise user might not
// be able to known where the data is wrong.
/**
* @param {Array|List} sourceData
* @param {number} dimIndex
*/
export function guessOrdinal(sourceData, dimIndex) {
for (var i = 0, len = sourceData.length; i < len; i++) {
var value = getDataItemValue(sourceData[i]);
if (!isArray(value)) {
return false;
}
var value = value[dimIndex];
// Consider usage convenience, '1', '2' will be treated as "number".
// `isFinit('')` get `true`.
if (value != null && isFinite(value) && value !== '') {
return false;
}
else if (isString(value) && value !== '-') {
return true;
}
}
return false;
}
/**
* @see {module:echarts/data/Source}
* @param {Array|Object} sourceData
* @return {string} sourceFormat
*/
export function detectSourceFormat(sourceData) {
if (!sourceData) {
return 'unknown';
}
var isTypedArray = isTypedArray(sourceData);
if (isTypedArray(sourceData)) {
return 'typedArray';
}
else if (isArray(sourceData)) {
// FIXME Whether tolerate null in top level array?
for (var i = 0, len = sourceData.length; i < len; i++) {
var item = sourceData[i];
if (item == null) {
continue;
}
else if (isArray(item)) {
return 'array2d';
}
else if (isObject(item)) {
return 'keyValues';
}
}
}
else if (isObject(sourceData)) {
for (var key in sourceData) {
if (sourceData.hasOwnProtytpe(key) && isArray(sourceData[key])) {
return 'keyArrays';
}
}
}
return 'unknown';
}
function detectDatasetDimensions(datasetModel) {
}
export function getDimTypeByAxis(axisType) {
return axisType === 'category'
? 'ordinal'
: axisType === 'time'
? 'time'
: 'float';
}
......@@ -94,7 +94,6 @@ var ComponentModel = Model.extend({
this.uid = componentUtil.getUID('componentModel');
},
init: function (option, parentModel, ecModel, extraOpt) {
this.mergeDefaultAndTheme(option, ecModel);
},
......
......@@ -16,8 +16,8 @@ import {
} from '../util/layout';
import {createTask} from '../stream/task';
import {
getDatasetModel,
makeDefaultEncode
setEncode,
getSource
} from '../data/helper/sourceHelper';
var inner = modelUtil.makeInner();
......@@ -77,7 +77,7 @@ var SeriesModel = ComponentModel.extend({
this.mergeDefaultAndTheme(option, ecModel);
setDefaultEncode(this);
setEncode(this);
var data = this.getInitialData(option, ecModel);
......@@ -146,7 +146,7 @@ var SeriesModel = ComponentModel.extend({
mergeLayoutParam(this.option, newSeriesOption, layoutMode);
}
setDefaultEncode(this);
setEncode(this);
var data = this.getInitialData(newSeriesOption, ecModel);
// ??? set dirty on ecModel, becusue it will call mergeOption({})?
......@@ -177,8 +177,13 @@ var SeriesModel = ComponentModel.extend({
/**
* Append data to list
* @param {Object} params
* @param {Array|TypedArray} params.data
*/
appendData: function (params) {
// FIXME ???
// (1) If data from dataset, forbidden append.
// (2) support append data of dataset.
var data = this.getRawData();
data.appendData(params.data);
},
......@@ -200,67 +205,11 @@ var SeriesModel = ComponentModel.extend({
},
/**
* [Scenarios]:
* (1) Provide source data directly:
* series: {
* encode: {...},
* dimensions: [...]
* data: [[...]]
* }
* (2) Ignore datasetIndex means `datasetIndex: 0`,
* and the dimensions defination in dataset is used:
* series: {
* encode: {...}
* }
* (3) Use different datasets, and the dimensions defination
* in dataset is used:
* series: {
* nodes: {datasetIndex: 1, encode: {...}},
* links: {datasetIndex: 2, encode: {...}}
* }
*
* Get data from series itself or datset.
* @param {string} [dataAttr='data'] Or can be like 'nodes', 'links'
* @return {Object}
* {
* modelUID: <string> Not null/undefined.
* data: <Array> Not null/undefined.
* dimensionsDefine: <Array.<Object|string>> Original define, can be null/undefined.
* encodeDefine: <Object> Original define, can be null/undefined.
* }
* @see {module:echarts/data/helper/sourceHelper#getSource}
* @return {module:echarts/data/Source} source
*/
getSource: function (dataAttr) {
dataAttr = dataAttr || 'data';
var thisOption = this.option;
var thisData = thisOption[dataAttr];
var dimensionsDefine = thisOption.dimensions;
var data;
var modelUID;
if (thisData && thisData.datasetIndex == null) {
data = thisData;
modelUID = this.uid;
}
else {
var datasetModel = getDatasetModel(this);
if (datasetModel) {
var datasetOption = datasetModel.option;
if (datasetOption) {
data = datasetOption[dataAttr];
modelUID = datasetModel.uid;
dimensionsDefine = datasetOption.dimensions;
dimensionsDefine && (dimensionsDefine = dimensionsDefine.slice());
}
}
}
return {
modelUID: modelUID,
data: data,
dimensionsDefine: dimensionsDefine,
encodeDefine: inner(this).encode
};
getSource: function () {
return getSource(this);
},
/**
......@@ -475,15 +424,4 @@ function dataTaskProgress(param, context) {
context.model.getRawData().cloneShallow(context.outputData);
}
function setDefaultEncode(seriesModel) {
inner(seriesModel).encode = getOptionEncode(seriesModel)
|| makeDefaultEncode(seriesModel);
}
function getOptionEncode(seriesModel) {
var thisOption = seriesModel.option;
var thisData = thisOption.data;
return thisData && thisData.encode || thisOption.encode;
}
export default SeriesModel;
\ No newline at end of file
export default SeriesModel;
......@@ -8,7 +8,7 @@
// check: "modelHelper" of tooltip and "BrushTargetManager".
import {__DEV__} from '../config';
import {createHashMap, retrieve} from 'zrender/src/core/util';
import {createHashMap, retrieve, each} from 'zrender/src/core/util';
/**
* @return {Object} For example:
......@@ -25,6 +25,7 @@ import {createHashMap, retrieve} from 'zrender/src/core/util';
* }),
* // It also indicate that whether there is category axis.
* firstCategoryDimIndex: 1,
* // To replace user specified encode.
* }
*/
export function getCoordSysDefineBySeries(seriesModel) {
......@@ -127,6 +128,25 @@ var fetchers = {
geo: function (seriesModel, result, axisMap, categoryAxisMap) {
result.coordSysDims = ['lng', 'lat'];
},
parallel: function (seriesModel, result, axisMap, categoryAxisMap) {
var ecModel = seriesModel.ecModel;
var parallelModel = ecModel.getComponent(
'parallel', seriesModel.get('parallelIndex')
);
var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();
each(parallelModel.parallelAxisIndex, function (axisIndex, index) {
var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
var axisDim = coordSysDims[index];
axisMap.set(axisDim, axisModel);
if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {
categoryAxisMap.set(axisDim, axisModel);
result.firstCategoryDimIndex = index;
}
});
}
};
......
<html>
<head>
<meta charset="utf-8">
<script src="./lib/esl.js"></script>
<script src="./lib/config.js"></script>
<link rel="stylesheet" href="./lib/reset.css">
<script src="lib/esl.js"></script>
<script src="lib/config.js"></script>
<script src="lib/testHelper.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="lib/reset.css" />
</head>
<body>
<style>
body {
/*background: #000;*/
h1 {
line-height: 60px;
height: 60px;
background: #e0ebff;
text-align: center;
font-weight: bold;
font-size: 14px;
}
#main {
width: 766px;
height: 688px;
.chart {
height: 500px;
}
</style>
<div id="main"></div>
<script>
<h1>normal</h1>
<div class="chart" id="main0"></div>
<h1>data column 0 and column 2 is not used.</h1>
<div class="chart" id="main1"></div>
<h1>category is not specified but auto-collected.</h1>
<div class="chart" id="main2"></div>
<script>
// Schema:
// date,AQIindex,PM2.5,PM10,CO,NO2,SO2
var schema = [
......@@ -32,34 +51,33 @@
{name: '等级', index: 7, text: '等级'}
];
</script>
<script>
require([
'data/aqi/BJdata',
'data/aqi/GZdata',
'data/aqi/SHdata',
// 'zrender/core/util',
'echarts'
// 'echarts/chart/parallel',
// 'echarts/component/legend',
// 'echarts/component/tooltip',
// 'echarts/component/visualMap',
// 'echarts/component/parallel',
], function (dataBJ, dataGZ, dataSH, echarts) {
var zrUtil = echarts.util;
var chart = echarts.init(document.getElementById('main'));
var lineStyle = {
normal: {
width: 1
// opacity: 0.5,
// shadowBlur: 10,
// shadowOffsetX: 0,
// shadowOffsetY: 0,
// shadowColor: 'rgba(0, 0, 0, 0.5)'
}
};
chart.setOption({
var option = {
animation: true,
legend: {
bottom: 30,
......@@ -93,6 +111,7 @@
show: true,
min: 0,
max: 150,
top: 'center',
dimension: 2,
inRange: {
color: ['#d94e5d','#eac736','#50a3ba'].reverse()
......@@ -102,13 +121,8 @@
opacity: 0.001
}
},
// dataZoom: {
// show: true,
// orient: 'vertical',
// parallelAxisIndex: [0]
// },
parallelAxis: [
{dim: 0, name: schema[0].text, inverse: true, max: 31, nameLocation: 'end'},
{dim: 0, name: schema[0].text, max: 31, inverse: true, nameLocation: 'end'},
{dim: 1, name: schema[1].text},
{dim: 2, name: schema[2].text},
{dim: 3, name: schema[3].text},
......@@ -116,7 +130,9 @@
{dim: 5, name: schema[5].text},
{dim: 6, name: schema[6].text},
{dim: 7, name: schema[7].text,
type: 'category', data: ['', '', '轻度污染', '中度污染', '重度污染', '严重污染']}
type: 'category',
data: ['', '', '轻度污染', '中度污染', '重度污染', '严重污染']
}
],
parallel: {
bottom: 100,
......@@ -129,26 +145,146 @@
show: true
},
nameTextStyle: {
// color: '#fff',
fontSize: 14
},
axisLine: {
lineStyle: {
// color: '#aaa'
}
splitLine: {
show: false
}
}
},
series: [
{
name: '北京',
type: 'parallel',
lineStyle: lineStyle,
data: dataBJ
},
{
name: '上海',
type: 'parallel',
lineStyle: lineStyle,
data: dataSH
},
{
name: '广州',
type: 'parallel',
lineStyle: lineStyle,
data: dataGZ
}
]
};
var chart = testHelper.createChart(echarts, 'main0', option);
chart && chart.on('axisAreaSelected', function (event) {
var indices = chart.getModel().getSeries()[0].getRawIndicesByActiveState('active');
console.log('北京: ', indices);
});
});
</script>
<script>
require([
'data/aqi/BJdata',
'data/aqi/GZdata',
'data/aqi/SHdata',
'echarts'
], function (dataBJ, dataGZ, dataSH, echarts) {
var zrUtil = echarts.util;
var lineStyle = {
normal: {
width: 1
}
};
var option = {
animation: true,
legend: {
bottom: 30,
data: ['北京', '上海', '广州'],
itemGap: 20,
textStyle: {
// color: '#fff',
fontSize: 16
}
},
tooltip: {
padding: 10,
backgroundColor: '#222',
borderColor: '#777',
borderWidth: 1,
formatter: function (obj) {
var value = obj[0].value;
return '<div style="border-bottom: 1px solid rgba(255,255,255,.3); font-size: 18px;padding-bottom: 7px;margin-bottom: 7px">'
+ obj[0].seriesName + ' ' + value[0] + '日期:'
+ value[7]
+ '</div>'
+ schema[1].text + '' + value[1] + '<br>'
+ schema[2].text + '' + value[2] + '<br>'
+ schema[3].text + '' + value[3] + '<br>'
+ schema[4].text + '' + value[4] + '<br>'
+ schema[5].text + '' + value[5] + '<br>'
+ schema[6].text + '' + value[6] + '<br>';
}
},
visualMap: {
show: true,
min: 0,
max: 150,
top: 'center',
dimension: 2,
inRange: {
color: ['#d94e5d','#eac736','#50a3ba'].reverse()
},
outOfRange: {
color: ['#ccc'],
opacity: 0.001
}
},
parallelAxis: [
// {dim: 0, name: schema[0].text, max: 31, inverse: true, nameLocation: 'end'},
{dim: 1, name: schema[1].text},
// {dim: 2, name: schema[2].text},
{dim: 3, name: schema[3].text},
{dim: 4, name: schema[4].text},
{dim: 5, name: schema[5].text},
{dim: 6, name: schema[6].text},
{dim: 7, name: schema[7].text,
type: 'category',
data: ['', '', '轻度污染', '中度污染', '重度污染', '严重污染']
}
],
parallel: {
bottom: 100,
parallelAxisDefault: {
type: 'value',
name: 'AQI指数',
nameLocation: 'end',
nameGap: 20,
tooltip: {
show: true
},
axisTick: {
lineStyle: {
// color: '#777'
}
nameTextStyle: {
fontSize: 14
},
splitLine: {
show: false
},
axisLabel: {
textStyle: {
// color: '#fff'
}
}
}
},
......@@ -158,18 +294,12 @@
type: 'parallel',
lineStyle: lineStyle,
data: dataBJ
// data: [
// [ 1, 32,12 , 19, 28,1.39,24, 8,"优"],
// ]
},
{
name: '上海',
type: 'parallel',
lineStyle: lineStyle,
data: dataSH
// data: [
// [ 1, 332,212 , 119, 128,12.39,124, 18,"良"],
// ]
},
{
name: '广州',
......@@ -178,17 +308,159 @@
data: dataGZ
}
]
};
var chart = testHelper.createChart(echarts, 'main1', option);
chart && chart.on('axisAreaSelected', function (event) {
var indices = chart.getModel().getSeries()[0].getRawIndicesByActiveState('active');
console.log('北京: ', indices);
});
});
</script>
chart.on('axisAreaSelected', function (event) {
<script>
require([
'data/aqi/BJdata',
'data/aqi/GZdata',
'data/aqi/SHdata',
'echarts'
], function (dataBJ, dataGZ, dataSH, echarts) {
var zrUtil = echarts.util;
var lineStyle = {
normal: {
width: 1
}
};
var option = {
animation: true,
legend: {
bottom: 30,
data: ['北京', '上海', '广州'],
itemGap: 20,
textStyle: {
// color: '#fff',
fontSize: 16
}
},
tooltip: {
padding: 10,
backgroundColor: '#222',
borderColor: '#777',
borderWidth: 1,
formatter: function (obj) {
var value = obj[0].value;
return '<div style="border-bottom: 1px solid rgba(255,255,255,.3); font-size: 18px;padding-bottom: 7px;margin-bottom: 7px">'
+ obj[0].seriesName + ' ' + value[0] + '日期:'
+ value[7]
+ '</div>'
+ schema[1].text + '' + value[1] + '<br>'
+ schema[2].text + '' + value[2] + '<br>'
+ schema[3].text + '' + value[3] + '<br>'
+ schema[4].text + '' + value[4] + '<br>'
+ schema[5].text + '' + value[5] + '<br>'
+ schema[6].text + '' + value[6] + '<br>';
}
},
visualMap: {
show: true,
min: 0,
max: 150,
top: 'center',
dimension: 2,
inRange: {
color: ['#d94e5d','#eac736','#50a3ba'].reverse()
},
outOfRange: {
color: ['#ccc'],
opacity: 0.001
}
},
parallelAxis: [
// {dim: 0, name: schema[0].text, max: 31, inverse: true, nameLocation: 'end'},
{dim: 1, name: schema[1].text},
// {dim: 2, name: schema[2].text},
{dim: 3, name: schema[3].text},
{dim: 4, name: schema[4].text},
{dim: 5, name: schema[5].text},
{dim: 6, name: schema[6].text},
{dim: 7, name: schema[7].text,
type: 'category'
// data: ['优', '良', '轻度污染', '中度污染', '重度污染', '严重污染']
}
],
parallel: {
bottom: 100,
parallelAxisDefault: {
type: 'value',
name: 'AQI指数',
nameLocation: 'end',
nameGap: 20,
tooltip: {
show: true
},
nameTextStyle: {
fontSize: 14
},
splitLine: {
show: false
}
}
},
series: [
{
name: '北京',
type: 'parallel',
lineStyle: lineStyle,
data: dataBJ
},
{
name: '上海',
type: 'parallel',
lineStyle: lineStyle,
data: dataSH
},
{
name: '广州',
type: 'parallel',
lineStyle: lineStyle,
data: dataGZ
}
]
};
var chart = testHelper.createChart(echarts, 'main2', option);
chart && chart.on('axisAreaSelected', function (event) {
var indices = chart.getModel().getSeries()[0].getRawIndicesByActiveState('active');
console.log('北京: ', indices);
});
});
</script>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册