提交 47456544 编写于 作者: P pah100

fix topology bug

上级 d2f2dcf2
......@@ -97,7 +97,10 @@ define(function(require) {
zrUtil.each(ComponentModel.getClassesByMainType(componentType), function (Clazz) {
arrayPush.apply(deps, Clazz.prototype.dependencies || []);
});
return deps;
// Ensure main type
return zrUtil.map(deps, function (type) {
return ComponentModel.parseComponentType(type).main;
});
}
return ComponentModel;
......
......@@ -97,7 +97,7 @@ define(function (require) {
var option = this.option;
var componentsMap = this._componentsMap;
var componentTypes = [];
var newCptTypes = [];
// 如果不存在对应的 component model 则直接 merge
zrUtil.each(newOption, function (componentOption, componentType) {
......@@ -112,13 +112,16 @@ define(function (require) {
}
}
else {
componentTypes.push(componentType);
newCptTypes.push(componentType);
}
});
// FIXME 这里 componentTypes 是新的 Option,在依赖处理上是否会有问题
// FIXME OPTION 同步是否要改回原来的
ComponentModel.topologicalTravel(componentTypes, function (componentType, dependencies) {
ComponentModel.topologicalTravel(
newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this
);
function visitComponent(componentType, dependencies) {
var newCptOptionList = newOption[componentType];
// Normalize
......@@ -158,7 +161,7 @@ define(function (require) {
this._componentsIdMap[componentModel.uid] = componentModel;
}
}
}, this);
}
// Backup data
zrUtil.each(componentsMap, function (components, componentType) {
......@@ -177,7 +180,10 @@ define(function (require) {
// Use determinSubType only when there is no existComponent.
: ComponentModel.determineSubType(componentType, newCptOption);
return newCptOption.type = subType;
// Dont make option.type === undefined, otherwise some problem will occur in merge.
subType && (newCptOption.type = subType);
return subType;
},
/**
......@@ -373,11 +379,15 @@ define(function (require) {
componentTypes.push(componentType);
});
ComponentModel.topologicalTravel(componentTypes, function (componentType, dependencies) {
zrUtil.each(componentsMap[componentType], function (component) {
component.restoreData();
});
});
ComponentModel.topologicalTravel(
componentTypes,
ComponentModel.getAllClassMainTypes(),
function (componentType, dependencies) {
zrUtil.each(componentsMap[componentType], function (component) {
component.restoreData();
});
}
);
},
/**
......
......@@ -123,10 +123,8 @@ define(function(require) {
var obj = storage[componentType.main];
if (obj && obj[IS_CONTAINER]) {
zrUtil.each(obj, function (ComponentClass, componentType) {
if (componentType !== IS_CONTAINER) {
result.push(ComponentClass);
}
zrUtil.each(obj, function (o, type) {
type !== IS_CONTAINER && result.push(o);
});
}
else {
......@@ -142,6 +140,17 @@ define(function(require) {
return !!storage[componentType.main];
};
/**
* @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']
*/
entity.getAllClassMainTypes = function () {
var types = [];
zrUtil.each(storage, function (obj, type) {
types.push(type);
});
return types;
};
entity.parseComponentType = parseComponentType;
function makeContainer(componentType) {
......@@ -187,10 +196,9 @@ define(function(require) {
if (!type) {
var componentTypeMain = parseComponentType(componentType).main;
var Clazz = storage[componentTypeMain];
Clazz
&& Clazz[IS_CONTAINER]
&& subTypeDefaulters[componentTypeMain]
&& subTypeDefaulters[componentTypeMain](option);
if (Clazz && Clazz[IS_CONTAINER] && subTypeDefaulters[componentTypeMain]) {
type = subTypeDefaulters[componentTypeMain](option);
}
}
return type;
};
......@@ -201,34 +209,42 @@ 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.
*
* If there are circle dependenceis, just ignore them.
*
*/
util.enableTopologicalTravel = function (entity, dependencyGetter) {
/**
* @public
* @param {Array.<string>} componentTypeList Target Component type list.
* @param {Array.<string>} targetNameList Target Component type list.
* Can be ['aa', 'bb', 'aa.xx']
* @param {Array.<string>} fullNameList By which we can build dependency graph.
* @param {Function} callback Params: componentType, dependencies.
* @param {Object} context Scope of callback.
*/
entity.topologicalTravel = function (componentTypeList, callback, context) {
if (!componentTypeList.length) {
entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {
if (!targetNameList.length) {
return;
}
var result = makeDepndencyGraph(componentTypeList);
var result = makeDepndencyGraph(fullNameList);
var graph = result.graph;
var stack = result.noEntryList;
if (!stack.length) {
throw new Error('Circle exists in dependency graph.');
}
var targetNameSet = {};
zrUtil.each(targetNameList, function (name) {
targetNameSet[name] = true;
});
while (stack.length) {
var currComponentType = stack.pop();
var currVertex = graph[currComponentType];
callback.call(context, currComponentType, currVertex.originalDeps.slice());
if (targetNameSet[currComponentType]) {
callback.call(context, currComponentType, currVertex.originalDeps.slice());
}
zrUtil.each(currVertex.successor, removeEdge);
}
......@@ -249,28 +265,28 @@ define(function(require) {
* entryCount: {number}
* }
*/
function makeDepndencyGraph(componentTypeList) {
function makeDepndencyGraph(fullNameList) {
var graph = {};
var noEntryList = [];
zrUtil.each(componentTypeList, function (componentType) {
zrUtil.each(fullNameList, function (name) {
var thisItem = createDependencyGraphItem(graph, componentType);
var originalDeps = thisItem.originalDeps = dependencyGetter(componentType);
var thisItem = createDependencyGraphItem(graph, name);
var originalDeps = thisItem.originalDeps = dependencyGetter(name);
var availableDeps = getAvailableDependencies(originalDeps, componentTypeList);
var availableDeps = getAvailableDependencies(originalDeps, fullNameList);
thisItem.entryCount = availableDeps.length;
if (thisItem.entryCount === 0) {
noEntryList.push(componentType);
noEntryList.push(name);
}
zrUtil.each(availableDeps, function (depComponentType) {
if (zrUtil.indexOf(thisItem.predecessor, depComponentType) < 0) {
thisItem.predecessor.push(depComponentType);
zrUtil.each(availableDeps, function (dependentName) {
if (zrUtil.indexOf(thisItem.predecessor, dependentName) < 0) {
thisItem.predecessor.push(dependentName);
}
var thatItem = createDependencyGraphItem(graph, depComponentType);
if (zrUtil.indexOf(thatItem.successor, depComponentType) < 0) {
thatItem.successor.push(componentType);
var thatItem = createDependencyGraphItem(graph, dependentName);
if (zrUtil.indexOf(thatItem.successor, dependentName) < 0) {
thatItem.successor.push(name);
}
});
});
......@@ -278,17 +294,17 @@ define(function(require) {
return {graph: graph, noEntryList: noEntryList};
}
function createDependencyGraphItem(graph, componentType) {
if (!graph[componentType]) {
graph[componentType] = {predecessor: [], successor: []};
function createDependencyGraphItem(graph, name) {
if (!graph[name]) {
graph[name] = {predecessor: [], successor: []};
}
return graph[componentType];
return graph[name];
}
function getAvailableDependencies(originalDeps, componentTypeList) {
function getAvailableDependencies(originalDeps, fullNameList) {
var availableDeps = [];
zrUtil.each(originalDeps, function (dep) {
zrUtil.indexOf(componentTypeList, dep) >= 0 && availableDeps.push(dep);
zrUtil.indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);
});
return availableDeps;
}
......
......@@ -23,7 +23,8 @@ describe('Component', function() {
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var result = [];
ComponentModel.topologicalTravel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
var allList = ComponentModel.getAllClassMainTypes();
ComponentModel.topologicalTravel(['m1', 'a1', 'a2'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']]]);
......@@ -32,8 +33,9 @@ describe('Component', function() {
testCase('topologicalTravel_a1IsAbsent', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a2'});
var allList = ComponentModel.getAllClassMainTypes();
var result = [];
ComponentModel.topologicalTravel(['m1', 'a2'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a2'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['m1', ['a1', 'a2']]]);
......@@ -43,8 +45,9 @@ describe('Component', function() {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var allList = ComponentModel.getAllClassMainTypes();
var result = [];
ComponentModel.topologicalTravel([], function (componentType, dependencies) {
ComponentModel.topologicalTravel([], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([]);
......@@ -54,11 +57,12 @@ describe('Component', function() {
ComponentModel.extend({type: 'a2'});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'm1', dependencies: ['a2']});
var allList = ComponentModel.getAllClassMainTypes();
var result = [];
ComponentModel.topologicalTravel(['a1', 'a2', 'm1'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['a1', 'a2', 'm1'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['m1', ['a2']], ['a1', []]]);
expect(result).toEqual([['a1', []], ['a2', []], ['m1', ['a2']]]);
});
testCase('topologicalTravel_diamond', function (ComponentModel) {
......@@ -66,8 +70,9 @@ describe('Component', function() {
ComponentModel.extend({type: 'a2', dependencies: ['a1']});
ComponentModel.extend({type: 'a3', dependencies: ['a1']});
ComponentModel.extend({type: 'm1', dependencies: ['a2', 'a3']});
var allList = ComponentModel.getAllClassMainTypes();
var result = [];
ComponentModel.topologicalTravel(['m1', 'a1', 'a2', 'a3'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a1', 'a2', 'a3'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a1', []], ['a3', ['a1']], ['a2', ['a1']], ['m1', ['a2', 'a3']]]);
......@@ -76,31 +81,59 @@ describe('Component', function() {
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: 'a1', dependencies: ['m2', 'a2', 'a3']});
ComponentModel.extend({type: 'a2'});
expect(function () {
ComponentModel.topologicalTravel(['m1', 'm2', 'a1']);
}).toThrowError(/Circl/);
ComponentModel.extend({type: 'a3'});
var allList = ComponentModel.getAllClassMainTypes();
var result = [];
ComponentModel.topologicalTravel(['m1', 'm2', 'a1', 'a2'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []]]);
// expect(function () {
// ComponentModel.topologicalTravel(['m1', 'm2', 'a1'], allList);
// }).toThrowError(/Circl/);
});
testCase('topologicalTravel_multipleEchartsInstance', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1'});
ComponentModel.extend({type: 'a2'});
var allList = ComponentModel.getAllClassMainTypes();
var result = [];
ComponentModel.topologicalTravel(['m1', 'a1', 'a2'], function (componentType, dependencies) {
ComponentModel.topologicalTravel(['m1', 'a1', 'a2'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']]]);
result = [];
ComponentModel.extend({type: 'm2', dependencies: ['a1', 'm1']});
ComponentModel.topologicalTravel(['m2', 'm1', 'a1', 'a2'], function (componentType, dependencies) {
var allList = ComponentModel.getAllClassMainTypes();
ComponentModel.topologicalTravel(['m2', 'm1', 'a1', 'a2'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a2', []], ['a1', []], ['m1', ['a1', 'a2']], ['m2', ['a1', 'm1']]]);
});
testCase('topologicalTravel_missingSomeNodeButHasDependencies', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a2', dependencies: ['a3']});
ComponentModel.extend({type: 'a3'});
ComponentModel.extend({type: 'a4'});
var result = [];
var allList = ComponentModel.getAllClassMainTypes();
ComponentModel.topologicalTravel(['a3', 'm1'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a3', []], ['m1', ['a1', 'a2']]]);
var result = [];
var allList = ComponentModel.getAllClassMainTypes();
ComponentModel.topologicalTravel(['m1', 'a3'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a3', []], ['m1', ['a1', 'a2']]]);
});
testCase('topologicalTravel_subType', function (ComponentModel) {
ComponentModel.extend({type: 'm1', dependencies: ['a1', 'a2']});
ComponentModel.extend({type: 'a1.aaa', dependencies: ['a2']});
......@@ -109,7 +142,8 @@ describe('Component', function() {
ComponentModel.extend({type: 'a3'});
ComponentModel.extend({type: 'a4'});
var result = [];
ComponentModel.topologicalTravel(['m1', 'a1', 'a2', 'a4'], function (componentType, dependencies) {
var allList = ComponentModel.getAllClassMainTypes();
ComponentModel.topologicalTravel(['m1', 'a1', 'a2', 'a4'], allList, function (componentType, dependencies) {
result.push([componentType, dependencies]);
});
expect(result).toEqual([['a4', []], ['a2',[]], ['a1', ['a2','a3','a4']], ['m1', ['a1', 'a2']]]);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册