提交 ce85666c 编写于 作者: P pah100

使 series继承自component。但是legend仍有些问题。原先用ecModel._seriesMap来“恰巧”达到“保存process前series”的作用。

现在没有这个东西了,但是legend的绘制,需要filerSeries之前的series(画symbol)。
如何backup data,是否应该filter,明天再讨论。
上级 69764d37
......@@ -3,10 +3,13 @@ define(function(require) {
'use strict';
var List = require('../../data/List');
var SeriesModel = require('../../model/Series');
return require('../../echarts').extendSeriesModel({
return SeriesModel.extend({
type: 'bar',
type: 'series.bar',
dependencies: ['xAxis', 'yAxis'],
getInitialData: function (option, ecModel) {
return List.fromArray(option.data, this, ecModel);
......
......@@ -3,10 +3,11 @@ define(function(require) {
'use strict';
var List = require('../../data/List');
var SeriesModel = require('../../model/Series');
return require('../../echarts').extendSeriesModel({
return SeriesModel.extend({
type: 'line',
type: 'series.line',
getInitialData: function (option, ecModel) {
return List.fromArray(option.data, this, ecModel);
......
......@@ -3,8 +3,9 @@ define(function(require) {
'use strict';
var List = require('../../data/List');
var SeriesModel = require('../../model/Series');
return require('../../echarts').extendSeriesModel({
return SeriesModel.extend({
type: 'pie',
......
......@@ -3,13 +3,14 @@ define(function (require) {
'use strict';
var List = require('../../data/List');
var SeriesModel = require('../../model/Series');
return require('../../echarts').extendSeriesModel({
return SeriesModel.extend({
type: 'scatter',
type: 'series.scatter',
getInitialData: function (option) {
return List.fromArray(option.data, 2, this);
getInitialData: function (option, ecModel) {
return List.fromArray(option.data, this, ecModel);
},
defaultOption: {
......
/**
* @file Data zoom model
*/
define(function(require) {
var List = require('../../data/List');
var zrUtil = require('zrender/core/util');
var env = require('zrender/core/env');
var echarts = require('../../echarts');
var helper = require('./helper');
return require('../../echarts').extendComponentModel({
return echarts.extendComponentModel({
type: 'dataZoom',
depends: ['xAxis', 'yAxis'],
dependencies: ['xAxis', 'yAxis', 'series'],
/**
* @override
*/
init: function (option, parentModel, ecModel) {
this.mergeDefaultAndTheme(option, ecModel);
/**
* @type {Object}
* @private
*/
this._state = {};
this.mergeOption();
},
/**
* @override
*/
mergeOption: function (newOption) {
var thisOption = this.option;
newOption && zrUtil.merge(thisOption, newOption);
// FIXME
// 实现?
// Disable realtime view update if canvas is not supported.
if (!zrUtil.canvasSupported()) {
if (!env.canvasSupported) {
thisOption.realtime = false;
}
// Init or reset zoom states.
var state = this._state;
var start = retrieveValue(thisOption.start, state.start, 0);
var end = retrieveValue(thisOption.end, state.end, 100);
// Auto reverse
(start > end) && (end = [start, start = end][0]);
state.start = start;
state.end = end;
// FIXME
// 是否有toolbox zoom控件时,自动加一个dataZoom option,而非和某个dataZoom option共用?
// dataZoom option中可加type来判断是普通还是toolbox还是移动端需要的图面拖拽。
// optionMerge时根据type进行merge。
this._resetTargetAxes(newOption);
// this._resetTargetSeries(newOption);
this._resetRange();
},
_resetTargetAxes: function (newOption) {
var thisOption = this.option;
var noAxisDefined = true;
helper.eachAxisDim(function (names) {
// Overlap these arrays but not merge.
var axisIndices = helper.toArray(helper.retrieveValue(
newOption[names.axisIndex], thisOption[names.axisIndex], []
));
var axisModels = this.dependentModels[names.axis];
// If not specified, set default.
if (axisModels.length && !axisIndices.length) {
for (var i = 0, len = axisModels.length; i < len; i++) {
if (axisModels[i].get('type') === 'category') {
axisIndices.push(i);
}
}
}
thisOption[names.axisIndex] = axisIndices;
if (axisIndices.length) {
noAxisDefined = false;
}
}, this);
if (noAxisDefined) {
// FIXME
// 这里是兼容ec2的写法(没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制),
// 但是实际是否需要Grid.js#getScaleByOption来判断(考虑time,log等axis type)?
// If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,
// dataZoom component auto adopts series that reference to
// both xAxis and yAxis which type is 'value'.
this.ecModel.eachSeries(function (seriesModel) {
if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {
helper.eachAxisDim(function (names) {
var axisIndices = thisOption[names.axisIndex];
var axisIndex = seriesModel.get(names.axisIndex);
if (zrUtil.indexOf(axisIndices, axisIndex) < 0) {
axisIndices.push(axisIndex);
}
});
}
}, this);
}
},
// Overlap these arrays but not merge.
_isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {
// FIXME
// zrUtil.merge是否有选项,决定array是否merge?
thisOption.xAxisIndex = retrieveValue(newOption.xAxisIndex, thisOption.xAxisIndex, []);
thisOption.yAxisIndex = retrieveValue(newOption.yAxisIndex, thisOption.yAxisIndex, []);
// Remove thisOption.start/end for consistence when processing merge.
// Consider this case:
// this.thisOption has start 10 and end 80,
// and state has start 20 and end 60,
// and newOption has start 40 but no end (means remain end 60).
thisOption.start = null;
thisOption.end = null;
// 需要series的xAxisIndex和yAxisIndex都首先自动设置上。
// 例如series.type === scatter时。
var is = true;
helper.eachAxisDim(function (names) {
var seriesAxisIndex = seriesModel.get(names.axisIndex);
var axisModel = this.dependentModels[names.axis][seriesAxisIndex];
if (!axisModel || axisModel.get('type') !== axisType) {
is = false;
}
}, this);
return is;
},
setStart: function (start) {
this._state.start = start;
_resetRange: function () {
var thisOption = this.option;
// TODO
// 对于一个轴受多个dataZoom控制的情况(如toolbox):
// datazoom改变时,不直接改变,而是发全局事件,监听:
// 如果轴是自己包含的轴,则自己改变start和end。
// 所有都改完后,重新走process流程。
// Determin which axes dataZoom.start/end and dataZoom.start2/end2 control.
// When only xAxisIndex or only yAxisIndex is specified, start/end controls them.
// targetDim === false means that both xAxisIndex and yAxisIndex are specified.
var targetDim;
helper.eachAxisDim(function (names) {
if (thisOption[names.axisIndex].length) {
targetDim = targetDim !== false ? false : names.dim;
}
});
// Otherwise, determine it by dataZoom.orient (compatibale with the logic in ec2.)
// targetDim === 'y' means start/end control 'y' and start2/end2 control 'x'.
var targetDim2;
if (targetDim === false) {
targetDim = thisOption.orient === 'vertical' ? 'y' : 'x';
targetDim2 = targetDim === 'x' ? 'y' : 'x';
}
var optAttrs = [];
optAttrs[targetDim] = {start: 'start', end: 'end'};
targetDim2 && (optAttrs[targetDim2] = {start: 'start2', end: 'end2'});
zrUtil.each(optAttrs, function (dimItem, targetDim) {
var axisModels = this.dependentModels[targetDim + 'Axis'];
var startValue = thisOption[dimItem.start];
var endValue = thisOption[dimItem.end];
// Auto reverse when start > end
if (startValue > endValue) {
startValue = [endValue, endValue = startValue][0];
}
// Set to axis and dataZoom
zrUtil.each(axisModels, function (axisModel) {
axisModel.setDataZoomRange(startValue, endValue);
});
thisOption[dimItem.start] = startValue;
thisOption[dimItem.end] = endValue;
});
if (!targetDim2) {
thisOption.start2 = thisOption.end2 = null;
}
},
setEnd: function (end) {
this._state.end = end;
/**
* @public
* @param {Object} param
* @param {number=} [param.start]
* @param {number=} [param.end]
* @param {number=} [param.start2]
* @param {number=} [param.end2]
*/
setRange: function (param) {
var thisOption = this.option;
param.start != null && (thisOption.start = param.start);
param.end != null && (thisOption.end = param.end);
param.start2 != null && (thisOption.start2 = param.start2);
param.end2 != null && (thisOption.end2 = param.end2);
this._resetRange();
},
setRange: function (start, end) {
this._state.start = start;
this._state.end = end;
/**
* @public
*/
getRange: function () {
var thisOption = this.option;
return {
start: thisOption.start,
end: thisOption.end,
star2: thisOption.star2,
end2: thisOption.end2
};
},
/**
* @protected
*/
defaultOption: {
zlevel: 0, // 一级层叠
z: 4, // 二级层叠
......@@ -90,26 +218,14 @@ define(function(require) {
showDetail: true,
// xAxisIndex: [], // 默认控制所有横向类目
// yAxisIndex: [], // 默认控制所有横向类目
// start: 0, // 默认为0
// end: 100, // 默认为全部 100%
start: 0, // 默认为0
end: 100, // 默认为全部 100%
start2: 0, // 默认为0
end2: 100, // 默认为全部 100%
realtime: true
// zoomLock: false // 是否锁定选择区域大小
}
});
// FIXME
// 公用?
/**
* If value1 is not null, then return value1, otherwise judget rest of values.
* @param {*...} values
* @return {*} Final value
*/
function retrieveValue(values) {
for (var i = 0, len = arguements.length; i < len; i++) {
if (arguements[i] != null) {
return arguements[i];
}
}
}
});
\ No newline at end of file
define(function (require) {
return require('../../echarts').extendComponentView({
var echarts = require('../../echarts');
var zrUtil = require('zrender/core/util');
var helper = require('./helper');
var unique = require('../../util/unique');
var retrieveValue = helper.retrieveValue;
// Constants
var DEFAULT_LOCATION_EDGE_GAP = 2;
var DEFAULT_FILLER_SIZE = 30;
return echarts.extendComponentView({
type: 'dataZoom',
init: function (echarts) {
this._location;
this._uid = unique.getUID('dataZoomView');
},
render: function (dataZoomModel, ecModel, api, event) {
// FIXME
// 需要区别用户事件在本component上触发的render和其他render。
// 后者不重新构造shape。否则难于实现拖拽。
this._dataZoomModel = dataZoomModel;
this._ecModel = ecModel;
this._api = api;
this._orient = dataZoomModel.get('orient');
if (!event || event.type !== 'dataZoom' || event.from !== this._uid) {
this.group.clear();
if (this.dataZoomModel.get('show') === false) {
return;
}
// Layout
this._updateLocation();
this._updateSliderRange({init: true});
this._updateWidgetSize();
// Render
this._renderBackground();
this._renderDataShadow();
}
},
/**
* 根据选项计算实体的位置坐标
*/
_updateLocation: function () {
var dataZoomModel = this._dataZoomModel;
var x;
var y;
var width;
var height;
// If some of x/y/width/height are not specified, auto-adapt according to target grid.
var gridRect = this._findGridRectForLocating();
if (this._orient === 'horizontal') { // Horizontal layout
width = retrieveValue(dataZoomModel.get('width'), gridRect.width);
height = retrieveValue(dataZoomModel.get('height'), DEFAULT_FILLER_SIZE);
x = retrieveValue(dataZoomModel.get('x'), gridRect.x);
y = retrieveValue(
dataZoomModel.get('y'), (api.getHeight() - height - DEFAULT_LOCATION_EDGE_GAP)
);
}
else { // Vertical layout
width = retrieveValue(dataZoomModel.get('width'), DEFAULT_FILLER_SIZE);
height = retrieveValue(dataZoomModel.get('height'), gridRect.height);
x = retrieveValue(dataZoomModel.get('x'), DEFAULT_LOCATION_EDGE_GAP);
y = retrieveValue(dataZoomModel.get('y'), gridRect.y);
}
this._location = {
x: x, y: y, width: width, height: height
};
},
/**
* @private
* @param {Object} dataZoomModel
* @param {Object} operation
* @param {boolean} [operation.init]
* @param {string} [operation.rangeArg] 'start' or 'end'
* @param {number} [operation.dx]
* @param {number} [operation.dy]
*/
_updateSliderRange: function (operation) {
// Based on this._location.
if (operation.init) {
var dataZoomModel = this._dataZoomModel;
var range = dataZoomModel.getRange();
var sliderTotalLength = this._getSliderTotalLength();
this._sliderRange = {
start: Math.round(range.start * 100 / sliderTotalLength),
end: Math.round(range.end * 100 / sliderTotalLength)
};
}
if (operation.rangeArg) {
this._sliderRange[operation.rangeArg] += this._getSliderDelta(operation);
}
},
_getSliderTotalLength: function () {
var location = this._location;
return this._orient === 'horizontal' ? location.width : location.height;
},
render: function (option) {
_getSliderDelta: function (operation) {
return retrieveValue(
this._orient === 'horizontal' ? operation.dx : operation.dy,
0
);
},
_normalizeToRange: function () {
var sliderTotalLength = this._getSliderTotalLength();
var sliderRange = this._sliderRange;
return {
start: sliderRange.start / sliderTotalLength * 100,
end: sliderRange.end / sliderTotalLength * 100
};
},
_updateWidgetSize: function () {
// Based on this._sliderRange and this._location.
var dataZoomModel = this._dataZoomModel;
var sliderRange = this._sliderRange;
var location = this._location;
var handleSize = dataZoomModel.get('handleSize');
var widgetSize = this._widgetSize = {};
if (dataZoomModel.get('orient') === 'horizontal') {
widgetSize.filler = {
x: location.x + sliderRange.start + handleSize,
y: location.y,
width: sliderRange.end - sliderRange.start - handleSize * 2,
height: location.height
};
}
else { // 'vertical'
widgetSize.filler = {
x: location.x,
y: location.y + sliderRange.start + handleSize,
width: location.width,
height: sliderRange.end - sliderRange.start - handleSize * 2
};
}
},
_findGridRectForLocating: function () {
// Find the grid coresponding to the first axis referred by dataZoom.
var axisModel;
var dataZoomModel = this._dataZoomModel;
var ecModel = this._ecModel;
helper.eachAxisDim(function (dimNames) {
var axisIndices = dataZoomModel.get(dimNames.axisIndex);
if (!axisModel && axisIndices.length) {
axisModel = ecModel.get(dimNames.axis)[axisIndices[0]];
}
});
return ecModel.getComponent('grid', axisModel.get('gridIndex')).getRect();
},
_renderBackground : function () {
var dataZoomModel = this._dataZoomModel;
var location = this._location;
this.group.push(new api.Rect({
// FIXME
// zlevel: this.getZlevelBase(),
// z: this.getZBase(),
hoverable:false,
style: {
x: location.x,
y: location.y,
width: location.width,
height: location.height,
color: dataZoomModel.get('backgroundColor')
}
}));
},
_renderDataShadow: function () {
// Data shadow
// TODO
},
_renderFiller: function () {
var dataZoomModel = this._dataZoomModel;
var orient = dataZoomModel.get('orient');
this._fillerShape = new api.Rect({
// FIXME
// zlevel: this.getZlevelBase(),
// z: this.getZBase(),
draggable: true,
ondrift: zrUtil.bind(this._onDrift, this, 'both'),
ondragend: zrUtil.bind(this._onDragEnd, this),
style: zrUtil.merge(
{
color: dataZoomModel.get('fillerColor'),
text: orient === 'horizontal' ? ':::' : '::',
textPosition : 'inside'
},
this._widgetSize
),
highlightStyle: {
brushType: 'fill',
color: 'rgba(0,0,0,0)'
}
});
this.group.push(this._fillerShape);
},
_renderHandle : function () {
var detail = this.zoomOption.showDetail ? this._getDetail() : {start: '',end: ''};
this._startShape = {
zlevel: this.getZlevelBase(),
z: this.getZBase(),
draggable : true,
style : {
iconType: 'rectangle',
x: this._location.x,
y: this._location.y,
width: this._handleSize,
height: this._handleSize,
color: this.zoomOption.handleColor,
text: '=',
textPosition: 'inside'
},
highlightStyle: {
text: detail.start,
brushType: 'fill',
textPosition: 'left'
},
ondrift: this._ondrift,
ondragend: this._ondragend
};
if (this.zoomOption.orient === 'horizontal') {
this._startShape.style.height = this._location.height;
this._endShape = zrUtil.clone(this._startShape);
this._startShape.style.x = this._fillerShae.style.x - this._handleSize,
this._endShape.style.x = this._fillerShae.style.x + this._fillerShae.style.width;
this._endShape.highlightStyle.text = detail.end;
this._endShape.highlightStyle.textPosition = 'right';
}
else {
this._startShape.style.width = this._location.width;
this._endShape = zrUtil.clone(this._startShape);
this._startShape.style.y = this._fillerShae.style.y + this._fillerShae.style.height;
this._startShape.highlightStyle.textPosition = 'bottom';
this._endShape.style.y = this._fillerShae.style.y - this._handleSize;
this._endShape.highlightStyle.text = detail.end;
this._endShape.highlightStyle.textPosition = 'top';
}
this._startShape = new IconShape(this._startShape);
this._endShape = new IconShape(this._endShape);
this.shapeList.push(this._startShape);
this.shapeList.push(this._endShape);
},
_onDrift : function (rangeArg, dx, dy) {
var dataZoomModel = this._dataZoomModel;
if (rangeArg === 'both' || dataZoomModel.get('zoomLock')) {
this._updateSliderRange({rangeArg: 'start', dx: dx, dy: dy});
this._updateSliderRange({rangeArg: 'end', dx: dx, dy: dy});
}
else { // rangeArg === 'start' or 'end'
this._updateSliderRange({rangeArg: rangeArg, dx: dx, dy: dy});
}
// FIXME
// refresh shape location
// FIXME
if (dataZoomModel.get('realtime')) {
// this._syncData();
}
// FIXME
if (this.zoomOption.showDetail) {
// var detail = this._getDetail();
// this._startShape.style.text = this._startShape.highlightStyle.text = detail.start;
// this._endShape.style.text = this._endShape.highlightStyle.text = detail.end;
// this._startShape.style.textPosition = this._startShape.highlightStyle.textPosition;
// this._endShape.style.textPosition = this._endShape.highlightStyle.textPosition;
}
this._api.dispatch({
type: 'dataZoom',
from: this._uid,
param: this._normalizeToRange()
});
// FIXME
return true;
},
_onDragEnd : function () {
// if (this.zoomOption.showDetail) {
// this._startShape.style.text = this._endShape.style.text = '=';
// this._startShape.style.textPosition = this._endShape.style.textPosition = 'inside';
// this.zr.modShape(this._startShape.id);
// this.zr.modShape(this._endShape.id);
// this.zr.refreshNextFrame();
// }
// this.isDragend = true;
},
}
});
});
\ No newline at end of file
/**
* @file Data zoom action
*/
define(function(require) {
var zrUtil = require('zrender/core/util');
var env = require('zrender/core/env');
var echarts = require('../../echarts');
var helper = require('./helper');
echarts.registerAction(function (event, ecModel) {
ecModel.eachComponent('dataZoom', zrUtil.curry(processSingleDataZoom, event, ecModel));
});
function processSingleDataZoom(event, ecModel, dataZoomModel) {
helper.eachAxisDim(function (dimNames) {
zrUtil.each(
dataZoomModel.get(dimNames.axisIndex),
zrUtil.curry(processSingleAxis, ecModel, dataZoomModel, dimNames)
);
});
}
});
\ No newline at end of file
......@@ -9,6 +9,8 @@ define(function(require) {
type: 'legend',
dependencies: ['series'],
init: function (option, parentModel, ecModel) {
this.mergeDefaultAndTheme(option, ecModel);
......
......@@ -18,6 +18,8 @@ define(function(require) {
// max: null, // 最大值
// scale: false, // 脱离0值比例,放大聚焦到最终_min,_max区间
// splitNumber: 5, // 分割段数,默认为5
dataZoomStart: 0, // 并不开放设置,而是由dataZoom设置
dataZoomEnd: 100, // 并不开放设置,而是由dataZoom设置
axisLine: { // 坐标轴线
show: true, // 默认显示,属性show控制显示与否
onZero: true,
......@@ -134,10 +136,22 @@ define(function(require) {
var AxisModel = require('../../model/Component').extend({
type: 'axis',
/**
* @type {module:echarts/coord/cartesian/Axis2D}
*/
axis: null
axis: null,
/**
* @public
* @param {number} start 0-100, null means remain current value.
* @param {number} end 0-100, null means remain current value.
*/
setDataZoomRange: function (start, end) {
var option = this.option;
start != null && (option.dataZoomStart = start);
end != null && (option.dataZoomEnd = end);
}
});
AxisModel.AxisX = AxisModel.extend({
......
......@@ -232,6 +232,18 @@ define(function(require) {
}, context);
return ret;
};
List.prototype['filter' + name] = function (cb, context) {
var newList = this.clone();
var elements = []
newList.each(function (item) {
if (cb.call(context || newList, item['get' + name]())) {
elements.push(item);
}
}, context);
newList.elements = elements;
return newList;
};
});
List.fromArray = function (data, seriesModel, ecModel) {
......
......@@ -206,7 +206,9 @@ define(function (require) {
var chart = chartsMap[id];
if (! chart) {
chart = ChartView.create(seriesModel.type);
chart = ChartView.create(
ComponentModel.parseComponentType(seriesModel.type).sub
);
if (chart) {
chart.init(this._extensionAPI);
chartsMap[id] = chart;
......@@ -232,7 +234,7 @@ define(function (require) {
else {
i++;
}
};
}
},
_prepareComponents: function (ecModel) {
......@@ -276,7 +278,7 @@ define(function (require) {
else {
i++;
}
};
}
},
/**
......@@ -416,13 +418,6 @@ define(function (require) {
visualCodingFuncs.push(visualCodingFunc);
},
/**
* @param {Object} opts
*/
extendSeriesModel: function (opts) {
return SeriesModel.extend(opts);
},
/**
* @param {Object} opts
*/
......
......@@ -9,9 +9,17 @@ define(function(require) {
var Model = require('./Model');
var zrUtil = require('zrender/core/util');
var arrayPush = Array.prototype.push;
var TYPE_DELIMITER = '.';
var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
/**
* Component model classes
* key: componentType,
* value:
* componentClass, when componentType is 'xxx'
* or Array.<componentClass>, when componentType is 'xxx.yy'
* @type {Object}
*/
var componentModelClasses = {};
......@@ -41,6 +49,7 @@ define(function(require) {
zrUtil.merge(option, ecModel.getTheme().get(this.type));
zrUtil.merge(option, this.defaultOption);
}
});
ComponentModel.extend = function (opts) {
......@@ -48,24 +57,62 @@ define(function(require) {
var componentType = opts.type;
if (componentType) {
if (componentModelClasses[componentType]) {
throw new Error('Component model "' + componentType + '" exists.');
componentType = ComponentModel.parseComponentType(componentType);
if (!componentType.sub) {
if (componentModelClasses[componentType.main]) {
throw new Error(componentType.main + 'exists');
}
componentModelClasses[componentType.main] = SubComponentModel;
}
else if (componentType.sub !== IS_CONTAINER) {
var container = makeContainer(componentType);
container[componentType.sub] = SubComponentModel;
}
componentModelClasses[componentType] = SubComponentModel;
}
return SubComponentModel;
};
ComponentModel.create = function (name, option, ecModel, dependentModels) {
if (componentModelClasses[name]) {
return new componentModelClasses[name](option, null, ecModel, dependentModels);
ComponentModel.getComponentModelClass = function (componentType, option) {
var fullComponentType = componentType;
if (option && option.type) {
fullComponentType = componentType + TYPE_DELIMITER + option.type;
}
var ComponentClass = getClassOrContainer(fullComponentType);
if (ComponentClass[IS_CONTAINER]) {
ComponentClass = ComponentClass[option.type];
}
return ComponentClass;
};
ComponentModel.has = function (name) {
return !!componentModelClasses[name];
ComponentModel.has = function (componentType) {
return !!getClassOrContainer(componentType);
};
ComponentModel.parseComponentType = function (componentType) {
var ret = {main: '', sub: ''};
if (componentType) {
componentType = componentType.split(TYPE_DELIMITER);
ret.main = componentType[0] || '';
ret.sub = componentType[1] || '';
}
return ret;
};
function makeContainer(componentType) {
var container = componentModelClasses[componentType.main];
if (!container || !container[IS_CONTAINER]) {
container = componentModelClasses[componentType.main] = {};
container[IS_CONTAINER] = true;
}
return container;
}
function getClassOrContainer(componentType) {
componentType = ComponentModel.parseComponentType(componentType);
return componentModelClasses[componentType.main];
}
/**
* Topological travel on Activity Network (Activity On Vertices).
* Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].
......@@ -118,8 +165,7 @@ define(function(require) {
zrUtil.each(componentTypeList, function (componentType) {
var thisItem = createDependencyGraphItem(graph, componentType);
var originalDeps = thisItem.originalDeps =
(componentModelClasses[componentType].prototype.dependencies || []).slice();
var originalDeps = thisItem.originalDeps = getDependencies(componentType);
var availableDeps = getAvailableDependencies(originalDeps, componentTypeList);
thisItem.entryCount = availableDeps.length;
......@@ -141,6 +187,23 @@ define(function(require) {
return {graph: graph, noEntryList: noEntryList};
}
function getDependencies(componentType) {
componentType = ComponentModel.parseComponentType(componentType);
var deps = [];
var obj = componentModelClasses[componentType.main];
if (obj && obj[IS_CONTAINER]) {
zrUtil.each(obj, function (ComponentClass, componentType) {
if (componentType !== IS_CONTAINER) {
arrayPush.apply(deps, ComponentClass.prototype.dependencies || []);
}
});
}
else if (obj) {
arrayPush.apply(deps, obj.prototype.dependencies || []);
}
return deps;
}
function createDependencyGraphItem(graph, componentType) {
if (!graph[componentType]) {
graph[componentType] = {predecessor: [], successor: []};
......
......@@ -9,7 +9,6 @@ define(function (require) {
var zrUtil = require('zrender/core/util');
var Model = require('./Model');
var SeriesModel = require('./Series');
var ComponentModel = require('./Component');
var globalDefault = require('./globalDefault');
......@@ -49,18 +48,6 @@ define(function (require) {
*/
this._componentsMap = {};
/**
* @type {Array.<module:echarts/model/Model}
* @private
*/
this._series = [];
/**
* @type {Object.<string, module:echarts/model/Model>}
* @private
*/
this._seriesMap = {};
/**
* @type {module:echarts/model/Model}
* @private
......@@ -100,82 +87,64 @@ define(function (require) {
mergeOption: function (newOption) {
var option = this.option;
zrUtil.each(newOption.series, function (series, idx) {
var seriesName = series.name || (series.type + idx);
var seriesMap = this._seriesMap;
var seriesModel = seriesMap[seriesName];
if (seriesModel) {
seriesModel.mergeOption(series, this);
}
else {
seriesModel = SeriesModel.create(series, this, idx);
seriesModel.name = seriesName;
seriesMap[seriesName] = seriesModel;
this._series.push(seriesModel);
}
}, this);
// 同步 Option
option.series = this._series.map(function (seriesModel) {
return seriesModel.option;
});
var componentsMap = this._componentsMap;
var components = this._components;
var modelNames = [];
var componentTypes = [];
// 如果不存在对应的 component model 则直接 merge
zrUtil.each(newOption, function (componentOption, name) {
if (!ComponentModel.has(name)) {
zrUtil.each(newOption, function (componentOption, componentType) {
if (!ComponentModel.has(componentType)) {
if (componentOption && typeof componentOption === 'object') {
option[name] = option[name] == null
option[componentType] = option[componentType] == null
? zrUtil.clone(componentOption)
: zrUtil.merge(option[name], componentOption);
: zrUtil.merge(option[componentType], componentOption);
}
else {
option[name] = componentOption;
option[componentType] = componentOption;
}
}
else {
modelNames.push(name);
componentTypes.push(componentType);
}
});
ComponentModel.topologicalTavel(modelNames, function (name, depends) {
var componentOption = newOption[name];
ComponentModel.topologicalTravel(componentTypes, function (componentType, dependencies) {
var componentOption = newOption[componentType];
// Normalize
if (!(componentOption instanceof Array)) {
if (!(zrUtil.isArray(componentOption))) {
componentOption = [componentOption];
}
if (!componentsMap[name]) {
componentsMap[name] = [];
if (!componentsMap[componentType]) {
componentsMap[componentType] = [];
}
for (var i = 0; i < componentOption.length; i++) {
var componentModel = componentsMap[name][i];
if (componentModel) {
componentModel.mergeOption(
componentOption[i], this
);
var componentModel = componentsMap[componentType][i];
var ComponentModelClass = ComponentModel.getComponentModelClass(
componentType, componentOption[i]
);
if (componentModel && componentModel instanceof ComponentModelClass) {
componentModel.mergeOption(componentOption[i], this);
}
else {
componentModel = ComponentModel.create(
name, componentOption[i], this,
this._getComponentsByTypes(depends)
componentModel = new ComponentModelClass(
componentOption[i], null, this,
this._getComponentsByTypes(dependencies), i
);
componentsMap[name][i] = componentModel;
componentsMap[componentType][i] = componentModel;
components.push(componentModel);
}
if (componentModel) {
// 同步 Option
if (componentOption instanceof Array) {
option[name] = option[name] || [];
option[name][i] = componentModel.option;
if (zrUtil.isArray(componentOption)) {
option[componentType] = option[componentType] || [];
option[componentType][i] = componentModel.option;
}
else {
option[name] = componentModel.option;
option[componentType] = componentModel.option;
}
}
}
......@@ -210,10 +179,16 @@ define(function (require) {
/**
* @param {string} name
* @return {Array.<module:echarts/model/Series>}
* @return {module:echarts/model/Series}
*/
getSeriesByName: function (name) {
return this._seriesMap[name];
var series = this._componentsMap.series;
for (var i = 0, len = series.length; i < len; i++) {
// name should be unique.
if (series[i].name === name) {
return series[i];
}
}
},
/**
......@@ -221,8 +196,8 @@ define(function (require) {
* @return {Array.<module:echarts/model/Series>}
*/
getSeriesByType: function (type) {
return zrUtil.filter(this._series, function (series) {
return series.type === type;
return zrUtil.filter(this._componentsMap.series, function (series) {
return ComponentModel.parseComponentType(series.type).sub === type;
});
},
......@@ -231,14 +206,14 @@ define(function (require) {
* @return {module:echarts/model/Series}
*/
getSeries: function (seriesIndex) {
return this._series[seriesIndex];
return this._componentsMap.series[seriesIndex];
},
/**
* @return {Array.<module:echarts/model/Series>}
*/
getSeriesAll: function () {
return this._series.slice();
return this._componentsMap.series.slice();
},
/**
......@@ -246,7 +221,7 @@ define(function (require) {
* @param {*} context
*/
eachSeries: function (cb, context) {
zrUtil.each(this._series, cb, context);
zrUtil.each(this._componentsMap.series, cb, context);
},
eachSeriesByType: function (type, cb, context) {
......@@ -258,38 +233,40 @@ define(function (require) {
* @param {*} context
*/
filterSeries: function (cb, context) {
this._series = zrUtil.filter(this._series, cb, context);
this._componentsMap.series = zrUtil.filter(
this._componentsMap.series, cb, context
);
},
save: function () {
var seriesList = this._componentsMap.series;
this._stack.push({
series: this._series.slice()
series: seriesList.slice()
});
var components = this._components;
var series = this._series;
var i;
for (i = 0; i < components.length; i++) {
components[i].save();
}
for (i = 0; i < series.length; i++) {
series[i].save();
for (i = 0; i < seriesList.length; i++) {
seriesList[i].save();
}
},
restore: function () {
if (this._stack.length) {
this._series = this._stack.pop().series;
this._componentsMap.series = this._stack.pop().series;
}
var seriesList = this._componentsMap.series;
var components = this._components;
var series = this._series;
var i;
for (i = 0; i < components.length; i++) {
components[i].restore();
}
for (i = 0; i < series.length; i++) {
series[i].restore();
for (i = 0; i < seriesList.length; i++) {
seriesList[i].restore();
}
},
......@@ -299,7 +276,7 @@ define(function (require) {
* @return {Object} key: {string} type, value: {Array.<Object>} models
*/
_getComponentsByTypes: function (types) {
if (!(types instanceof Array)) {
if (!zrUtil.isArray(types)) {
types = types ? [types] : [];
}
......
......@@ -24,6 +24,14 @@ define(function (require) {
this.option = option;
/**
* @type {Object}
* @protected
*/
this.ecModel = ecModel;
/**
* key: componentType
* value: Array.<Object> Component model list, can not be null.
* @type {Object}
* @readOnly
*/
......
......@@ -2,10 +2,10 @@ define(function(require) {
'use strict';
var Model = require('./Model');
var zrUtil = require('zrender/core/util');
var ComponentModel = require('./Component');
var SeriesModel = Model.extend({
var SeriesModel = ComponentModel.extend({
type: '',
......@@ -14,6 +14,11 @@ define(function(require) {
*/
seriesIndex: 0,
/**
* @readOnly
*/
name: '',
// coodinateSystem will be injected in the echarts/CoordinateSystem
coordinateSystem: null,
......@@ -23,26 +28,38 @@ define(function(require) {
*/
defaultOption: null,
init: function (seriesOption, parentModel, ecModel, seriesIndex) {
init: function (option, parentModel, ecModel, dependentModels, seriesIndex) {
/**
* @type {number}
*/
this.seriesIndex = seriesIndex;
zrUtil.merge(seriesOption, ecModel.getTheme().get(this.type));
this.mergeDefaultAndTheme(option, ecModel);
zrUtil.merge(seriesOption, this.defaultOption);
var seriesName = this.get('name');
if (seriesName == null) {
seriesName = this.get('type') + '' + seriesIndex;
}
this.name += seriesName + '';
/**
* @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}
* @private
*/
this._data = this.getInitialData(seriesOption, ecModel);
this._data = this.getInitialData(option, ecModel);
this._stack = [];
},
mergeDefaultAndTheme: function (option, ecModel) {
zrUtil.merge(
option,
ecModel.getTheme().get(ComponentModel.parseComponentType(this.type).sub)
);
zrUtil.merge(option, this.defaultOption);
},
mergeOption: function (newSeriesOption, ecModel) {
this._data = this.getInitialData(newSeriesOption, ecModel);
},
......@@ -70,33 +87,5 @@ define(function(require) {
}
});
var seriesModelClassesStore = {};
/**
* Extend a SeriesModel
*/
SeriesModel.extend = function (opts) {
var ExtendedSeriesModel = Model.extend.call(this, opts);
if (opts.type) {
if (seriesModelClassesStore[opts.type]) {
// Warning
}
seriesModelClassesStore[opts.type] = ExtendedSeriesModel;
}
return ExtendedSeriesModel;
};
/**
* Create a SeriesModel by a given option
*/
SeriesModel.create = function (option, ecModel, seriesIndex) {
var chartType = option.type;
var ExtendedSeriesModel = seriesModelClassesStore[chartType];
if (! ExtendedSeriesModel) {
// Error
}
return new ExtendedSeriesModel(option, null, ecModel, seriesIndex);
};
return SeriesModel;
});
\ No newline at end of file
define(function(require) {
'use strict';
var unique = {};
var base = 0;
var DELIMITER = '_';
/**
* @public
* @param {string} type
* @return {string}
*/
unique.getUID = function (type) {
// Considering the case of crossing js context,
// use Math.random to make id as unique as possible.
return [(type || ''), base++, Math.random()].join(DELIMITER);
};
/**
* @public
* @param {string} uid
* @return {string} Type
*/
unique.getType = function (uid) {
if (uid) {
return uid.split(DELIMITER)[0];
}
};
return unique;
});
\ No newline at end of file
......@@ -10,6 +10,6 @@ require.config({
location: '../../zrender-dev3.0/src',
name: 'zrender'
}
],
urlArgs: '_v_=' + +new Date()
]//,
// urlArgs: '_v_=' + +new Date()
});
\ No newline at end of file
......@@ -6,7 +6,7 @@ describe('Component', function() {
utHelper.resetPackageLoader(done);
});
describe('topologicalTavel', function () {
describe('topologicalTravel', function () {
function testCase(name, doTest) {
it(name, function (done) {
......@@ -18,88 +18,102 @@ describe('Component', function() {
}
function xtestCase() {} // jshint ignore:line
testCase('topologicalTavel_base', function (ComponentModel) {
testCase('topologicalTravel_base', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']]]);
});
testCase('topologicalTavel_a1IsAbsent', function (ComponentModel) {
testCase('topologicalTravel_a1IsAbsent', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel(['m1', 'a2'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['m1', ['a1', 'a2']]]);
});
testCase('topologicalTavel_empty', function (ComponentModel) {
testCase('topologicalTravel_empty', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel([], function (componentType, dependencies) {
ComponentModel.topologicalTravel([], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([]);
});
testCase('topologicalTavel_isolate', function (ComponentModel) {
testCase('topologicalTravel_isolate', function (ComponentModel) {
ComponentModel.extend({type: 'a2'});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'm1', dependencies: ['a2']});
var result = [];
ComponentModel.topologicalTavel(['a1', 'a2', 'm1'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['a1', 'a2', 'm1'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['m1', ['a2']], ['a1', []]]);
});
testCase('topologicalTavel_diamond', function (ComponentModel) {
testCase('topologicalTravel_diamond', function (ComponentModel) {
ComponentModel.extend({type: 'a1', dependencies: []});
ComponentModel.extend({type: 'a2', dependencies: ['a1']});
ComponentModel.extend({type: 'a3', dependencies: ['a1']});
ComponentModel.extend({type: 'm1', dependencies: ['a2', 'a3']});
var result = [];
ComponentModel.topologicalTavel(['m1', 'a1', 'a2', 'a3'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a1', 'a2', 'a3'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a1', []], ['a3', ['a1']], ['a2', ['a1']], ['m1', ['a2', 'a3']]]);
});
testCase('topologicalTavel_loop', function (ComponentModel) {
testCase('topologicalTravel_loop', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'm2', dependencies: ['m1', 'a2']});
ComponentModel.extend({type: 'a1', dependencies: ['m2', 'a2']});
ComponentModel.extend({type: 'a2'});
expect(function () {
ComponentModel.topologicalTavel(['m1', 'm2', 'a1']);
ComponentModel.topologicalTravel(['m1', 'm2', 'a1']);
}).toThrowError(/Circl/);
});
testCase('topologicalTavel_multipleEchartsInstance', function (ComponentModel) {
testCase('topologicalTravel_multipleEchartsInstance', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']]]);
result = [];
ComponentModel.extend({type: 'm2', dependencies: ['a1', 'm1']});
ComponentModel.topologicalTavel(['m2', 'm1', 'a1', 'a2'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m2', 'm1', 'a1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']], ['m2', ['a1', 'm1']]]);
});
testCase('topologicalTravel_subType', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1.aaa', dependencies: ['a2']});
ComponentModel.extend({type: 'a1.bbb', dependencies: ['a3', 'a4']});
ComponentModel.extend({type: 'a2'});
ComponentModel.extend({type: 'a3'});
ComponentModel.extend({type: 'a4'});
var result = [];
ComponentModel.topologicalTravel(['m1', 'a1', 'a2', 'a4'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a4', []], ['a2',[]], ['a1', ['a2','a3','a4']], ['m1', ['a1', 'a2']]]);
});
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册