feat: darg combo with states

This commit is contained in:
baizn 2020-05-06 12:22:11 +08:00 committed by Yanyan Wang
parent 4a8171a104
commit 8c7550956d
5 changed files with 147 additions and 105 deletions

View File

@ -37,6 +37,8 @@ export default {
return {
enableDelegate: false,
delegateStyle: {},
// 拖动节点过程中是否只改变 Combo 的大小,而不改变其结构
onlyChangeComboSize: false,
// 拖动过程中目标 combo 状态样式
activeState: '',
selectedState: 'selected'
@ -100,8 +102,6 @@ export default {
this.point = {};
this.originPoint = {};
this.itemStates = {}
this.origin = {
x: evt.x,
y: evt.y
@ -195,7 +195,10 @@ export default {
if (this.activeState) {
graph.setItemState(item, this.activeState, false)
}
graph.updateComboTree(combo, targetModel.id)
// 将 Combo 放置到某个 Combo 上面时,只有当 onlyChangeComboSize 为 false 时候才更新 Combo 结构
if (!this.onlyChangeComboSize) {
graph.updateComboTree(combo, targetModel.id)
}
}
})
@ -242,102 +245,107 @@ export default {
const model = item.getModel()
// 拖动结束时计算拖入还是拖出, 需要更新 combo
// 1. 是否将当前 combo 拖出了 父 combo
// 2. 是否将当前 combo 拖入了新的 combo
const type = item.getType()
if (type === 'combo') {
const parentId = model.parentId
// 拖动 Combo 结束后,如果 onlyChangeComboSize 值为 true 则只更新 Combo 位置,不更新结构
if (this.onlyChangeComboSize) {
graph.updateCombos()
} else {
// 拖动结束时计算拖入还是拖出, 需要更新 combo
// 1. 是否将当前 combo 拖出了 父 combo
// 2. 是否将当前 combo 拖入了新的 combo
const type = item.getType()
if (type === 'combo') {
const parentId = model.parentId
let currentBBox = null
const parentCombo = this.getParentCombo(parentId)
let currentBBox = null
const parentCombo = this.getParentCombo(parentId)
// 当只有存在 parentCombo 时才处理拖出的情况
if (parentCombo) {
if (this.enableDelegate) {
currentBBox = this.delegateShape.getBBox()
} else {
currentBBox = item.getBBox()
}
const { x: cx, y: cy, centerX, centerY, width } = currentBBox;
//判断是否拖出了 combo需要满足
// 1、有 parent
// 2、拿拖动的对象和它父parent比较
const parentBBox = parentCombo.getBBox()
const { minX, minY, maxX, maxY, centerX: pcx, centerY: pcy, width: w } = parentBBox;
// 拖出了父 combo
// 如果直接拖出到了 父 combo 周边,则不用计算距离圆心距离
if (cx <= minX || cx >= maxX || cy <= minY || cy >= maxY) {
if (this.activeState) {
graph.setItemState(parentCombo, this.activeState, false)
// 当只有存在 parentCombo 时才处理拖出的情况
if (parentCombo) {
if (this.enableDelegate) {
currentBBox = this.delegateShape.getBBox()
} else {
currentBBox = item.getBBox()
}
isDragOut = true
// 表示正在拖出操作
graph.updateComboTree(item as ICombo)
} else {
// 拖动的 combo 和要进入的 combo 之间的距离
const disX = centerX - pcx
const disY = centerY - pcy
// 圆心距离
const distance = 2 * Math.sqrt(disX * disX + disY * disY)
const { x: cx, y: cy, centerX, centerY, width } = currentBBox;
// 拖出的还在父 combo 包围盒范围内,但实际上已经拖出去了
if ((width + w) - distance < 0.8 * width) {
//判断是否拖出了 combo需要满足
// 1、有 parent
// 2、拿拖动的对象和它父parent比较
const parentBBox = parentCombo.getBBox()
const { minX, minY, maxX, maxY, centerX: pcx, centerY: pcy, width: w } = parentBBox;
// 拖出了父 combo
// 如果直接拖出到了 父 combo 周边,则不用计算距离圆心距离
if (cx <= minX || cx >= maxX || cy <= minY || cy >= maxY) {
if (this.activeState) {
graph.setItemState(parentCombo, this.activeState, false)
}
isDragOut = true
// 表示正在拖出操作
graph.updateComboTree(item as ICombo)
} else {
// 拖动的 combo 和要进入的 combo 之间的距离
const disX = centerX - pcx
const disY = centerY - pcy
// 圆心距离
const distance = 2 * Math.sqrt(disX * disX + disY * disY)
// 拖出的还在父 combo 包围盒范围内,但实际上已经拖出去了
if ((width + w) - distance < 0.8 * width) {
if (this.activeState) {
graph.setItemState(parentCombo, this.activeState, false)
}
isDragOut = true
graph.updateComboTree(item as ICombo)
}
}
}
}
// 拖入
if (!this.endComparison && !isDragOut) {
// 判断是否拖入了 父 Combo需要满足
// 1、拖放最终位置是 combo且不是父 Combo
// 2、拖动 Combo 进入到非父 Combo 超过 50%
const combos = graph.getCombos()
const sourceBBox = item.getBBox()
// 拖入
if (!this.endComparison && !isDragOut) {
// 判断是否拖入了 父 Combo需要满足
// 1、拖放最终位置是 combo且不是父 Combo
// 2、拖动 Combo 进入到非父 Combo 超过 50%
const combos = graph.getCombos()
const sourceBBox = item.getBBox()
const { centerX, centerY, width } = sourceBBox
const { centerX, centerY, width } = sourceBBox
// 参与计算的 Combo需要排除掉
// 1、拖动 combo 自己
// 2、拖动 combo 的 parent
// 3、拖动 Combo 的 children
const calcCombos = combos.filter(combo => {
const cmodel = combo.getModel() as ComboConfig
// 被拖动的是最外层的 Combo无 parent排除自身和子元素
if (!model.parentId) {
// 参与计算的 Combo需要排除掉
// 1、拖动 combo 自己
// 2、拖动 combo 的 parent
// 3、拖动 Combo 的 children
const calcCombos = combos.filter(combo => {
const cmodel = combo.getModel() as ComboConfig
// 被拖动的是最外层的 Combo无 parent排除自身和子元素
if (!model.parentId) {
return cmodel.id !== model.id && !this.currentItemChildCombos.includes(cmodel.id)
}
return cmodel.id !== model.id && !this.currentItemChildCombos.includes(cmodel.id)
}
return cmodel.id !== model.id && !this.currentItemChildCombos.includes(cmodel.id)
})
})
calcCombos.map(combo => {
const current = combo.getModel()
const { centerX: cx, centerY: cy, width: w } = combo.getBBox()
calcCombos.map(combo => {
const current = combo.getModel()
const { centerX: cx, centerY: cy, width: w } = combo.getBBox()
// 拖动的 combo 和要进入的 combo 之间的距离
const disX = centerX - cx
const disY = centerY - cy
// 圆心距离
const distance = 2 * Math.sqrt(disX * disX + disY * disY)
// 拖动的 combo 和要进入的 combo 之间的距离
const disX = centerX - cx
const disY = centerY - cy
// 圆心距离
const distance = 2 * Math.sqrt(disX * disX + disY * disY)
if (this.activeState) {
graph.setItemState(combo, this.activeState, false)
}
if (this.activeState) {
graph.setItemState(combo, this.activeState, false)
}
if ((width + w) - distance > 0.8 * width) {
graph.updateComboTree(item as ICombo, current.id)
}
})
}
if ((width + w) - distance > 0.8 * width) {
graph.updateComboTree(item as ICombo, current.id)
}
})
}
}
// 删除delegate shape
@ -347,11 +355,6 @@ export default {
this.delegateShape = null
}
for (let itemId in this.itemStates) {
const states = this.itemStates[itemId]
each(states, state => graph.setItemState(item, state, true))
}
const parentCombo = this.getParentCombo(model.parentId)
if (parentCombo && this.activeState) {
graph.setItemState(parentCombo, this.activeState, false)
@ -362,7 +365,6 @@ export default {
this.origin = null
this.originPoint = null
this.targets.length = 0
this.itemStates = {}
},
/**
@ -419,12 +421,6 @@ export default {
const x: number = evt.x - origin.x + this.point[itemId].x;
const y: number = evt.y - origin.y + this.point[itemId].y;
if (item.getStates().length > 0) {
const states = item.getStates()
this.itemStates[itemId] = [...states]
each(states, state => graph.setItemState(item, state, false))
}
graph.updateItem(item, { x, y });
},

View File

@ -19,6 +19,8 @@ export default {
delegateStyle: {},
// 是否开启delegate
enableDelegate: false,
// 拖动节点过程中是否只改变 Combo 的大小,而不改变其结构
onlyChangeComboSize: false,
// 拖动过程中目标 combo 状态样式
comboActiveState: '',
selectedState: 'selected'
@ -126,26 +128,43 @@ export default {
this.delegateRect = null;
}
if (this.target) {
const delegateShape = this.target.get('delegateShape');
if (delegateShape) {
delegateShape.remove();
this.target.set('delegateShape', null);
}
// 当开启 delegate 时,拖动结束后需要更新所有已选中节点的位置
if (this.get('enableDelegate')) {
this.targets.map(node => this.update(node, evt));
}
if (this.targets.length > 0) {
// 获取所有已经选中的节点
this.targets.forEach(node => this.update(node, evt));
} else if (this.target) {
this.update(this.target, evt);
const graph: IGraph = this.graph
// 拖动结束后是动态改变 Combo 大小还是将节点从 Combo 中删除
if (this.onlyChangeComboSize) {
// 拖动节点结束后,动态改变 Combo 的大小
graph.updateCombos()
} else {
// 拖放到了最外面如果targets中有 combo则删除掉
if (!this.targetCombo) {
this.targets.map((node: INode) => {
// 拖动的节点有 comboId即是从其他 combo 中拖出时才处理
const model = node.getModel()
if (model.comboId) {
graph.updateComboTree(node)
}
})
} else {
const targetComboModel = this.targetCombo.getModel()
this.targets.map((node: INode) => {
const nodeModel = node.getModel()
if (nodeModel.comboId !== targetComboModel.id) {
graph.updateComboTree(node, targetComboModel.id)
}
})
}
}
this.point = {};
this.origin = null;
this.originPoint = {};
this.targets.length = 0;
this.target = null;
this.targetCombo = null;
},
/**
* combo

View File

@ -944,7 +944,23 @@ export default class Graph extends EventEmitter implements IGraph {
*/
public updateItem(item: Item | string, cfg: Partial<NodeConfig> | EdgeConfig): void {
const itemController: ItemController = this.get('itemController');
itemController.updateItem(item, cfg);
let currentItem
if (isString(item)) {
currentItem = this.findById(item)
} else {
currentItem = item
}
const type = currentItem.getType()
const states = [...currentItem.getStates()]
if (type === 'combo') {
each(states, state => this.setItemState(currentItem, state, false))
}
itemController.updateItem(currentItem, cfg);
if (type === 'combo') {
each(states, state => this.setItemState(currentItem, state, true))
}
}
/**
@ -1368,7 +1384,15 @@ export default class Graph extends EventEmitter implements IGraph {
}
const childItem = itemMap[child.id];
if (childItem && childItem.getType() === 'combo') {
// 更新具体的 Combo 之前先清除所有的已有状态,以免将 state 中的样式更新为 Combo 的样式
const states = [...childItem.getStates()]
each(states, state => this.setItemState(childItem, state, false))
// 更新具体的 Combo
itemController.updateCombo(childItem, child.children);
// 更新 Combo 后,还原已有的状态
each(states, state => this.setItemState(childItem, state, true))
}
return true;
});
@ -1413,6 +1437,7 @@ export default class Graph extends EventEmitter implements IGraph {
if (parentId) {
const parentCombo = this.findById(parentId) as ICombo
if (parentCombo) {
// 将元素添加到 parentCombo 中
parentCombo.addChild(uItem as ICombo | INode)
}
}
@ -1420,6 +1445,7 @@ export default class Graph extends EventEmitter implements IGraph {
if (oldParentId) {
const parentCombo = this.findById(oldParentId) as ICombo
if (parentCombo) {
// 将元素从 parentCombo 中移除
parentCombo.removeChild(uItem as ICombo | INode)
}
}

View File

@ -121,6 +121,7 @@ export interface ModeOption {
activeState?: string;
comboActiveState?: string;
selectedState?: string;
onlyChangeComboSize?: boolean;
includeEdges?: boolean;
direction?: 'x' | 'y';
shouldUpdate?: (e: IG6GraphEvent) => boolean;

View File

@ -320,7 +320,7 @@ describe('drag-combo', () => {
// fill: '#f00',
// fontSize: 20
// },
stroke: '#f00'
stroke: 'blue'
},
active: {
stroke: 'red'