Merge remote-tracking branch 'remotes/origin/dev3.0.0' into daily_19-10-11

This commit is contained in:
yilin.qyl 2019-01-14 10:20:05 +08:00
commit a4968a35b1
3 changed files with 325 additions and 24 deletions

View File

@ -165,17 +165,23 @@ class Item {
return;
}
self.updatePosition(model);
const cfg = this.getShapeCfg(model); // 可能会附加额外信息
const cfg = self.getShapeCfg(model); // 可能会附加额外信息
const keyShape = shapeFactory.draw(shapeType, cfg, group);
const states = self.get('states');
if (keyShape) {
keyShape.isKeyShape = true;
self.set('keyShape', keyShape);
}
this._resetStates(shapeFactory, shapeType);
}
_resetStates(shapeFactory, shapeType) {
const self = this;
const states = self.get('states');
Util.each(states, state => {
shapeFactory.setState(shapeType, state, true, self);
});
}
/**
* 获取当前元素的所有状态
* @return {Array} 元素的所有状态
@ -270,26 +276,33 @@ class Item {
const shapeFactory = this.get('shapeFactory');
const shape = model.shape;
const newModel = Util.mix({}, model, cfg);
// 判定是否允许更新
// 1. 注册的元素node, edge允许更新
// 2. 更新的信息中没有指定 shape
// 3. 更新信息中指定了 shape 同时等于原先的 shape
if (shapeFactory.shouldUpdate(shape) && newModel.shape === shape) {
const updateCfg = this.getShapeCfg(newModel);
// 如果 x,y 发生改变,则重置位置
if (newModel.x !== model.x || newModel.y !== model.y) {
this.updatePosition(newModel);
}
if (!(cfg && this._isOnlyMove(cfg))) { // 仅移动时不进行更新
const onlyMove = this._isOnlyMove(cfg);
// 仅仅移动位置时,既不更新,也不重绘
if (onlyMove) {
this.updatePosition(newModel);
} else {
// 判定是否允许更新
// 1. 注册的元素node, edge允许更新
// 2. 更新的信息中没有指定 shape
// 3. 更新信息中指定了 shape 同时等于原先的 shape
if (shapeFactory.shouldUpdate(shape) && newModel.shape === shape) {
const updateCfg = this.getShapeCfg(newModel);
// 如果 x,y 发生改变,则重置位置
// 非 onlyMove ,不代表不 move
if (newModel.x !== model.x || newModel.y !== model.y) {
this.updatePosition(newModel);
}
// 如果 x,y 发生改变,则重置位置
shapeFactory.update(shape, updateCfg, this);
// 设置 model 在更新后,防止在更新时取原始 model
this.set('model', newModel);
// 更新后重置节点状态
this._resetStates(shapeFactory, shape);
} else { // 如果不满足上面 3 种状态,重新绘制
this.set('model', newModel);
// 绘制元素时,需要最新的 model
this.draw();
}
// 设置 model 在更新后,防止在更新时取原始 model
this.set('model', newModel);
} else { // 如果不满足上面 3 种状态,重新绘制
this.set('model', newModel);
// 绘制元素时,需要最新的 model
this.draw();
}
this.afterUpdate();
}
@ -304,9 +317,15 @@ class Item {
// 是否仅仅移动
_isOnlyMove(cfg) {
if (!cfg) {
return false; // 刷新时不仅仅移动
}
// 不能直接使用 cfg.x && cfg.y 这类的判定,因为 0 的情况会出现
const existX = !Util.isNil(cfg.x);
const existY = !Util.isNil(cfg.y);
const keys = Object.keys(cfg);
return (keys.length === 1 && (cfg.x || cfg.y)) // 仅有一个字段,包含 x 或者 包含 y
|| (keys.length === 2 && cfg.x && cfg.y); // 两个字段,同时有 x同时有 y
return (keys.length === 1 && (existX || existY)) // 仅有一个字段,包含 x 或者 包含 y
|| (keys.length === 2 && existX && existY); // 两个字段,同时有 x同时有 y
}
/**

181
test/bugs/issue-601-spec.js Normal file
View File

@ -0,0 +1,181 @@
const expect = require('chai').expect;
const G6 = require('../../src/');
const div = document.createElement('div');
div.id = 'issue-601';
document.body.appendChild(div);
const data = {
nodes: [{
id: 'node1',
x: 100,
y: 200,
shape: 'hsf'
}, {
id: 'node2',
x: 300,
y: 200,
label: '萧庆',
labelCfg: {
position: 'bottom'
},
shape: 'image',
img: 'https://img2.bosszhipin.com/boss/avatar/avatar_13.png'
}, {
id: 'node3',
x: 400,
y: 100,
shape: 'image',
label: '语雀',
labelCfg: {
position: 'bottom'
},
img: 'https://gw.alipayobjects.com/zos/rmsportal/XuVpGqBFxXplzvLjJBZB.svg'
}, {
id: 'node4',
x: 400,
y: 400,
shape: 'image',
img: '//img.alicdn.com/tfs/TB1_uT8a5ERMeJjSspiXXbZLFXa-143-59.png'
}],
edges: [{
id: 'edge1',
target: 'node2',
source: 'node1',
style: {
endArrow: true
},
label: '你好,我好',
labelCfg: {
style: {
stroke: 'white',
lineWidth: 5
} // 加白边框
}
}, {
source: 'node2',
target: 'node3',
style: {
endArrow: true
},
shape: 'quadratic',
label: '过去的线',
labelCfg: {
refY: -10,
refX: 0,
autoRotate: true,
style: {
fill: 'red'
}
}
}, {
source: 'node3',
target: 'node2',
style: {
endArrow: true,
stroke: 'red'
},
size: 2,
shape: 'quadratic',
label: '回来的线',
labelCfg: {
refY: -10,
refX: 0,
autoRotate: true,
style: {
fill: 'red'
}
}
}, {
source: 'node3',
target: 'node4',
style: {
endArrow: true,
stroke: 'blue',
lineDash: [ 2, 2 ]
},
shape: 'my-edge',
label: '随便连连\n换行',
curveLevel: 4,
labelCfg: {
refY: -20,
refX: 0,
autoRotate: true,
style: {
fill: 'red'
}
}
}]
};
G6.registerNode('hsf', {
draw(cfg, group) {
const shape = group.addShape('circle', {
attrs: {
x: 36,
y: 40,
r: 55,
stroke: '#71cd00',
lineWidth: 5
}
});
group.addShape('image', {
attrs: {
x: 0 - 15,
y: 0 - 22,
width: 100,
height: 100,
img: 'https://g.alicdn.com/cm-design/arms-trace/1.0.155/styles/armsTrace/images/APP.png'
}
});
group.addShape('text', {
attrs: {
x: 15,
y: 85,
text: 'HSF',
fontSize: 15,
stroke: 'black'
}
});
group.addShape('text', {
attrs: {
x: 35,
y: 100,
text: cfg.id,
fontSize: 13,
stroke: 'black',
textAlign: 'center',
textBaseline: 'top'
}
});
return shape;
}
});
describe('#601', () => {
const graph = new G6.Graph({
container: 'issue-601',
width: 500,
height: 500,
modes: {
default: [ 'drag-node' ]
}
});
it('drag test', () => {
graph.data(data);
graph.render();
const node = graph.findById('node1');
const shape = node.get('keyShape');
// 更新节点的位置 shape 不销毁
graph.update(node, { x: 10, y: 20 });
expect(shape.get('destroyed')).not.eql(true);
// drag 之类事件的 target 还没改好,等改好了,触发 drag 事件
});
it('clear', () => {
graph.destroy();
expect(graph.destroyed).eql(true);
});
});

View File

@ -1,7 +1,7 @@
const expect = require('chai').expect;
const G = require('@antv/g');
const Node = require('../../../src/item/node');
const Shape = require('../../../src/shape/');
const div = document.createElement('div');
div.id = 'node-spec';
document.body.appendChild(div);
@ -133,7 +133,45 @@ describe('node', () => {
expect(shape.attr('fillOpacity')).eql(0.8);
});
it('get link point, no anchor', () => {
it('update with state', () => {
Shape.registerNode('custom-rect', {
setState(name, value, node) {
// const group = node.getContainer();
const shape = node.get('keyShape');
if (name === 'selected') {
if (value) {
shape.attr('fill', 'red');
} else {
shape.attr('fill', 'white');
}
}
}
}, 'rect');
const group = new G.Group();
const node = new Node({
model: {
x: 100,
y: 100,
size: [ 20, 40 ],
shape: 'custom-rect',
label: 'ni hao'
},
group,
states: [ 'active' ]
});
const shape = node.get('keyShape');
expect(shape.attr('fill')).eql('white');
node.setState('selected', true);
expect(shape.attr('fill')).eql('red');
node.update({ x: 10 });
expect(shape.attr('fill')).eql('red');
node.update({ size: [ 20, 30 ] });
expect(shape.attr('fill')).eql('red');
node.setState('selected', false);
expect(shape.attr('fill')).eql('white');
});
it('get link point, without anchor', () => {
const group = new G.Group();
const node = new Node({
model: {
@ -198,4 +236,67 @@ describe('node', () => {
expect(snap(point1.y, 100)).eql(true);
});
it('only move', () => {
const group = new G.Group();
const node = new Node({
model: {
x: 100,
y: 100,
size: [ 20, 20 ],
shape: 'rect',
anchorPoints: [
[ 0.5, 0 ], [ 1, 0.5 ], [ 0.5, 1 ], [ 0, 0.5 ]
]
},
group
});
expect(node.get('model').x).eql(100);
expect(node.get('model').y).eql(100);
node.update({ x: 200 });
expect(node.get('model').x).eql(200);
expect(node.get('model').y).eql(100);
node.update({ y: 200 });
expect(node.get('model').x).eql(200);
expect(node.get('model').y).eql(200);
});
it('register shape only draw', () => {
Shape.registerNode('my-node-test', {
draw(cfg, group) {
const shape = group.addShape('circle', {
attrs: {
x: 0,
y: 0,
r: cfg.size
}
});
return shape;
}
});
const group = new G.Group();
const node = new Node({
model: {
x: 100,
y: 100,
size: 10,
shape: 'my-node-test'
},
group
});
const shape = node.get('keyShape');
expect(!!shape.get('destroyed')).eql(false);
node.update({ x: 0, y: 20 });
expect(!!shape.get('destroyed')).eql(false);
node.update({ size: 20 });
expect(shape.get('destroyed')).eql(true);
expect(shape).not.eql(node.get('keyShape'));
Shape.Node['my-node-test'] = null;
});
});