提交 a07029fc 编写于 作者: P pah100

enhance dependency implementation

上级 25913cb1
/**
* @file Data zoom processor
*/
define(function (require) {
var echarts = require('../../echarts');
var helper = require('./helper');
var zrUtil = require('zrender/core/util');
echarts.registerProcessor(function (ecModel) {
ecModel.eachComponent('dataZoom', zrUtil.curry(processSingleDataZoom, ecModel));
});
// FIXME
// originalData是放在原来的data中(这样不会被接下来的processor处理)
// 还是新创建个series(type="dataZoom")专门存originalData(这样会被processor处理,但是一些地方得特别判断type=='dataZoom')
// 同样,Axis的originalData放在哪里。
// 其中:
// originalData在ec2中的用途:
// (1)画dataZoom组件(包括具体数值)
// (2)在packData时会用getRealDataIndex
// TODO
// undo redo
function processSingleDataZoom(ecModel, dataZoomModel) {
helper.eachAxisDim(function (dimNames) {
zrUtil.each(
dataZoomModel.get(dimNames.axisIndex),
zrUtil.curry(processSingleAxis, ecModel, dataZoomModel, dimNames)
);
});
}
function processSingleAxis(ecModel, dataZoomModel, dimNames, axisIndex) {
// TODO
// backup axis data
var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);
var axisData = axisModel.get('data');
if (axisData) {
var dataLength = axisData.length;
var start = Math.floor(axisModel.get('dataZoomStart') / 100 * dataLength);
var end = Math.ceil(axisModel.get('dataZoomEnd') / 100 * dataLength);
// Only category axis has property 'data's.
axisData = axisData.slice(start, end);
var seriesModels = getTargetSeriesModelsByAxis(
ecModel, dataZoomModel, axisIndex, dimNames
);
zrUtil.each(seriesModels, function (seriesModel) {
// FIXME
// data的backup
// FIXME
// 如何filter,
// 是根据data自己存的信息(如dimension)来判断(这比较直接,但是现在list里存的信息没清楚),
// 还是根据axis type来判断(比较枚举不太好)
// var axisType = axisModel.get('type');
// FIXME
// 这里仅仅处理了list类型
var seriesData = seriesModel.getData();
seriesModel.setData(
seriesData['filter' + dimNames.dim.toUpperCase()](start, end)
);
// FIXME
// 对于数值轴,还要考虑log等情况
// FIXME
// 对于时间河流图,还要考虑是否须整块移除。
});
}
}
function getTargetSeriesModelsByAxis(ecModel, dataZoomModel, axisIndex, dimNames) {
var seriesModels = [];
ecModel.eachSeries(function (seriesModel) {
if (axisIndex === seriesModel.get(dimNames.axisIndex)) {
seriesModels.push(seriesModel);
}
});
return seriesModels;
}
});
/**
* @file Data zoom helper
*/
define(function(require) {
var zrUtil = require('zrender/core/util');
var helper = {};
var AXIS_DIMS = ['x', 'y'];
// FIXME
// 公用?
helper.eachAxisDim = function (callback, scope) {
zrUtil.each(AXIS_DIMS, function (axisDim) {
var names = {
axisIndex: axisDim + 'AxisIndex',
axis: axisDim + 'Axis',
dim: axisDim
};
callback.call(scope, names);
});
};
// FIXME
// 公用?
/**
* If value1 is not null, then return value1, otherwise judget rest of values.
* @param {*...} values
* @return {*} Final value
*/
helper.retrieveValue = function (values) {
for (var i = 0, len = arguments.length; i < len; i++) {
if (arguments[i] != null) {
return arguments[i];
}
}
};
// FIXME
// 公用?
/**
* If value is not array, then translate it to array.
* @param {*} value
* @return {Array} [value] or value
*/
helper.toArray = function (value) {
return zrUtil.isArray(value) ? value : (value == null ? [] : [value]);
};
return helper;
});
\ No newline at end of file
......@@ -44,10 +44,9 @@ define(function(require) {
});
ComponentModel.extend = function (opts) {
var SubComponentModel = Model.extend.call(this, opts);
var componentType = opts.type;
if (componentType) {
if (componentModelClasses[componentType]) {
throw new Error('Component model "' + componentType + '" exists.');
......@@ -57,9 +56,9 @@ define(function(require) {
return SubComponentModel;
};
ComponentModel.create = function (name, option, ecModel) {
ComponentModel.create = function (name, option, ecModel, dependentModels) {
if (componentModelClasses[name]) {
return new componentModelClasses[name](option, null, ecModel);
return new componentModelClasses[name](option, null, ecModel, dependentModels);
}
};
......@@ -69,25 +68,20 @@ define(function(require) {
/**
* Topological travel on Activity Network (Activity On Vertices).
* Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].
* If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.
*
* @public
* @param {Array.<string>} componentTypeList Target Component type list.
* @param {Function} callback Params: componentType, depends.
* @param {Function} callback Params: componentType, dependencies.
*/
ComponentModel.topologicalTavel = function (componentTypeList, callback, scope) {
ComponentModel.topologicalTravel = function (componentTypeList, callback, scope) {
if (!componentTypeList.length) {
return;
}
var dependencyGraph = makeDepndencyGraph(componentTypeList);
var stack = [];
var entryCount = [];
zrUtil.each(componentTypeList, function (componentType) {
entryCount[componentType] = dependencyGraph[componentType].predecessor.length;
if (entryCount[componentType] === 0) {
stack.push(componentType);
}
});
var result = makeDepndencyGraph(componentTypeList);
var graph = result.graph;
var stack = result.noEntryList;
if (!stack.length) {
throw new Error('Circle exists in dependency graph.');
......@@ -95,14 +89,14 @@ define(function(require) {
while (stack.length) {
var currComponentType = stack.pop();
var currVertex = dependencyGraph[currComponentType];
callback.call(scope, currComponentType, currVertex.predecessor.slice());
var currVertex = graph[currComponentType];
callback.call(scope, currComponentType, currVertex.originalDeps.slice());
zrUtil.each(currVertex.successor, removeEdge);
}
function removeEdge(succComponentType) {
entryCount[succComponentType]--;
if (entryCount[succComponentType] === 0) {
graph[succComponentType].entryCount--;
if (graph[succComponentType].entryCount === 0) {
stack.push(succComponentType);
}
}
......@@ -112,37 +106,54 @@ define(function(require) {
* DepndencyGraph: {Object}
* key: conponentType,
* value: {
* predecessor: [conponentTypes...]
* successor: [conponentTypes...]
* successor: [conponentTypes...],
* originalDeps: [conponentTypes...],
* entryCount: {number}
* }
*/
function makeDepndencyGraph(componentTypeList) {
var dependencyGraph = {};
var graph = {};
var noEntryList = [];
zrUtil.each(componentTypeList, function (componentType) {
var thisItem = createDependencyGraphItem(dependencyGraph, componentType);
var ModelClass = componentModelClasses[componentType];
var depends = ModelClass.prototype.depends || [];
zrUtil.each(depends, function (depComponentType) {
var thisItem = createDependencyGraphItem(graph, componentType);
var originalDeps = thisItem.originalDeps =
(componentModelClasses[componentType].prototype.dependencies || []).slice();
var availableDeps = getAvailableDependencies(originalDeps, componentTypeList);
thisItem.entryCount = availableDeps.length;
if (thisItem.entryCount === 0) {
noEntryList.push(componentType);
}
zrUtil.each(availableDeps, function (depComponentType) {
if (zrUtil.indexOf(thisItem.predecessor, depComponentType) < 0) {
thisItem.predecessor.push(depComponentType);
}
var thatItem = createDependencyGraphItem(dependencyGraph, depComponentType);
var thatItem = createDependencyGraphItem(graph, depComponentType);
if (zrUtil.indexOf(thatItem.successor, depComponentType) < 0) {
thatItem.successor.push(componentType);
}
});
});
return dependencyGraph;
return {graph: graph, noEntryList: noEntryList};
}
function createDependencyGraphItem(dependencyGraph, componentType) {
if (!dependencyGraph[componentType]) {
dependencyGraph[componentType] = {predecessor: [], successor: []};
function createDependencyGraphItem(graph, componentType) {
if (!graph[componentType]) {
graph[componentType] = {predecessor: [], successor: []};
}
return dependencyGraph[componentType];
return graph[componentType];
}
function getAvailableDependencies(originalDeps, componentTypeList) {
var availableDeps = [];
zrUtil.each(originalDeps, function (dep) {
zrUtil.indexOf(componentTypeList, dep) >= 0 && availableDeps.push(dep);
});
return availableDeps;
}
return ComponentModel;
......
......@@ -19,23 +19,33 @@ describe('Component', function() {
function xtestCase() {} // jshint ignore:line
testCase('topologicalTavel_base', function (ComponentModel) {
ComponentModel.extend({type: 'm1', depends: ['a1', 'a2']});
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel(['m1', 'a1', 'a2'], function (componentType, depends) {
result.push([componentType, depends]);
ComponentModel.topologicalTavel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']]]);
});
testCase('topologicalTavel_a1IsAbsent', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel(['m1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['m1', ['a1', 'a2']]]);
});
testCase('topologicalTavel_empty', function (ComponentModel) {
ComponentModel.extend({type: 'm1', depends: ['a1', 'a2']});
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTavel([], function (componentType, depends) {
result.push([componentType, depends]);
ComponentModel.topologicalTavel([], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([]);
});
......@@ -43,50 +53,50 @@ describe('Component', function() {
testCase('topologicalTavel_isolate', function (ComponentModel) {
ComponentModel.extend({type: 'a2'});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'm1', depends: ['a2']});
ComponentModel.extend({type: 'm1', dependencies: ['a2']});
var result = [];
ComponentModel.topologicalTavel(['a1', 'a2', 'm1'], function (componentType, depends) {
result.push([componentType, depends]);
ComponentModel.topologicalTavel(['a1', 'a2', 'm1'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['m1', ['a2']], ['a1', []]]);
});
testCase('topologicalTavel_diamond', function (ComponentModel) {
ComponentModel.extend({type: 'a1', depends: []});
ComponentModel.extend({type: 'a2', depends: ['a1']});
ComponentModel.extend({type: 'a3', depends: ['a1']});
ComponentModel.extend({type: 'm1', depends: ['a2', 'a3']});
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, depends) {
result.push([componentType, depends]);
ComponentModel.topologicalTavel(['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) {
ComponentModel.extend({type: 'm1', depends: ['a1', 'a2']});
ComponentModel.extend({type: 'm2', depends: ['m1', 'a2']});
ComponentModel.extend({type: 'a1', depends: ['m2', 'a2']});
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']);
}).toThrowError(/Circl/);
});
testCase('topologicalTavel_re', function (ComponentModel) {
ComponentModel.extend({type: 'm1', depends: ['a1', 'a2']});
testCase('topologicalTavel_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, depends) {
result.push([componentType, depends]);
ComponentModel.topologicalTavel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']]]);
result = [];
ComponentModel.extend({type: 'm2', depends: ['a1', 'm1']});
ComponentModel.topologicalTavel(['m2', 'm1', 'a1', 'a2'], function (componentType, depends) {
result.push([componentType, depends]);
ComponentModel.extend({type: 'm2', dependencies: ['a1', 'm1']});
ComponentModel.topologicalTavel(['m2', 'm1', 'a1', 'a2'], function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']], ['m2', ['a1', 'm1']]]);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册