diff --git a/CHANGELOG.md b/CHANGELOG.md index ecf0079fab7..916860d4341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # ChangeLog +#### 4.3.8 + +- fix: addBehavior with behavior string name, closes: #3020; +- fix: drag-node shouldEnd does not stop the dragging node behavior, closes: #3173; +- fix: drag-combo fails to merge combo with enableDelegate, closes: #3137; +- fix: uncombo does not trigger afterremoveitem event, closes: #3179; +- fix: error label background position when the edge label has position start, closes: #3129; +- fix: destroyed graph judgement, closes: #3203; +- fix: edge click event will not be triggered when the contextmenu is configure with trigger click, closes: #3201; +- feat: drag-combo with shouldEnd, closes: #3202; +- chore: information for failing to download image, closes: #2980; + #### 4.3.7 - fix: update edge to be horizontal and the label is on wrong position; diff --git a/packages/core/package.json b/packages/core/package.json index 060f873d2e9..44ddc620849 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g6-core", - "version": "0.3.7", + "version": "0.3.8", "description": "A Graph Visualization Framework in JavaScript", "keywords": [ "antv", diff --git a/packages/core/src/element/edge.ts b/packages/core/src/element/edge.ts index 5ffd39ae0f3..de9033e8dd7 100644 --- a/packages/core/src/element/edge.ts +++ b/packages/core/src/element/edge.ts @@ -273,26 +273,21 @@ const singleEdge: ShapeOptions = { return style; } + let bgOffsetX = offsetX - backgroundWidth / 2; + if (labelCfg.position === 'start') { + bgOffsetX = offsetX - padding[2]; + } else if (labelCfg.position === 'end') { + bgOffsetX = offsetX - backgroundWidth; + } + let offsetStyle = getLabelPosition( pathShape, pointPercent, - offsetX - backgroundWidth / 2, + bgOffsetX, offsetY + backgroundHeight / 2, autoRotate, ); - const rad = offsetStyle.angle; - - if (rad > (1 / 2) * Math.PI && rad < ((3 * 1) / 2) * Math.PI) { - offsetStyle = getLabelPosition( - pathShape, - pointPercent, - offsetX + backgroundWidth / 2, - offsetY + backgroundHeight / 2, - autoRotate, - ); - } - if (autoRotate) { style.x = offsetStyle.x; style.y = offsetStyle.y; @@ -379,18 +374,16 @@ const singleEdge: ShapeOptions = { } if (labelStyle.background) { - const rect = this.drawLabelBg(cfg, group, label); + const rect = this.drawLabelBg(cfg, group, label, labelStyle, rotate); const labelBgClassname = this.itemType + CLS_LABEL_BG_SUFFIX; rect.set('classname', labelBgClassname); label.toFront(); } return label; }, - drawLabelBg(cfg: ModelConfig, group: IGroup, label: IElement) { + drawLabelBg(cfg: ModelConfig, group: IGroup, label: IElement, labelStyle: any, rotate: number) { const { labelCfg: defaultLabelCfg } = this.options as ModelConfig; const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg); - const labelStyle = this.getLabelStyle!(cfg, labelCfg, group); - const rotate = labelStyle.rotate; const style = this.getLabelBgStyleByPosition(label, cfg, labelCfg, group); delete style.rotate; diff --git a/packages/core/src/global.ts b/packages/core/src/global.ts index 00136a73f94..87d5a3cc616 100644 --- a/packages/core/src/global.ts +++ b/packages/core/src/global.ts @@ -64,7 +64,7 @@ const colorSet = { }; export default { - version: '0.3.7', + version: '0.3.8', rootContainerClassName: 'root-container', nodeContainerClassName: 'node-container', edgeContainerClassName: 'edge-container', diff --git a/packages/core/src/graph/controller/item.ts b/packages/core/src/graph/controller/item.ts index 1811ae86795..419baab2732 100644 --- a/packages/core/src/graph/controller/item.ts +++ b/packages/core/src/graph/controller/item.ts @@ -174,7 +174,9 @@ export default class ItemController { // collapse the combo if the collapsed is true in the model if (model.collapsed) { setTimeout(() => { - graph.collapseCombo(item as ICombo); + if (!item.destroyed) { + graph.collapseCombo(item as ICombo); + } }, 0); } } diff --git a/packages/core/src/graph/controller/mode.ts b/packages/core/src/graph/controller/mode.ts index 7c592c58ad5..35ec116b816 100644 --- a/packages/core/src/graph/controller/mode.ts +++ b/packages/core/src/graph/controller/mode.ts @@ -194,6 +194,7 @@ export default class ModeController { ); } + this.formatModes(); this.setMode(this.mode); return this; diff --git a/packages/core/src/graph/graph.ts b/packages/core/src/graph/graph.ts index 982f87f915c..162ac6e429b 100644 --- a/packages/core/src/graph/graph.ts +++ b/packages/core/src/graph/graph.ts @@ -1638,6 +1638,7 @@ export default abstract class AbstractGraph extends EventEmitter implements IAbs comboItems.splice(index, 1); delete itemMap[comboId]; comboItem.destroy(); + this.emit('afterremoveitem', { item: comboItem }); } // find the parent to remove the combo from the combo's brothers array and add the combo's children to the combo's brothers array in the tree if (parentId && treeToBeUncombo && subtree.id === parentId) { diff --git a/packages/core/src/util/graphic.ts b/packages/core/src/util/graphic.ts index 297c3f16777..f911095e7ac 100644 --- a/packages/core/src/util/graphic.ts +++ b/packages/core/src/util/graphic.ts @@ -274,7 +274,7 @@ export const getLabelPosition = ( }; if (rotate) { - if (rad > (1 / 2) * PI && rad < ((3 * 1) / 2) * PI) { + if (rad > 0.5 * PI && rad < 1.5 * PI) { rad -= PI; } return { diff --git a/packages/core/tests/unit/graph/controller/mode-spec.ts b/packages/core/tests/unit/graph/controller/mode-spec.ts index cc91c089a6d..94650c68855 100644 --- a/packages/core/tests/unit/graph/controller/mode-spec.ts +++ b/packages/core/tests/unit/graph/controller/mode-spec.ts @@ -62,7 +62,7 @@ describe('Mode Controller', () => { modeController.manipulateBehaviors('drag', 'dragx', true); expect(modeController.modes.dragx.length).toBe(1); - expect(modeController.modes.dragx[0]).toEqual('drag'); + expect(modeController.modes.dragx[0].type).toEqual('drag'); modeController.manipulateBehaviors(['drag', 'zoom'], ['out', 'xxx'], true); expect(Object.keys(modeController.modes).length).toBe(5); diff --git a/packages/core/tests/unit/graph/controller/state-spec.ts b/packages/core/tests/unit/graph/controller/state-spec.ts index f29f05d6f63..85e52e56732 100644 --- a/packages/core/tests/unit/graph/controller/state-spec.ts +++ b/packages/core/tests/unit/graph/controller/state-spec.ts @@ -60,7 +60,7 @@ describe('graph state controller', () => { const modes = graph.get('modes'); expect(Object.keys(modes)).toEqual(['default']); - expect(modes.default).toEqual(['activate-relations']); + expect(modes.default[0].type).toEqual('activate-relations'); graph.removeBehaviors('activate-relations', 'default'); diff --git a/packages/element/package.json b/packages/element/package.json index 3beca1ee850..09c7ef89b9a 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g6-element", - "version": "0.3.7", + "version": "0.3.8", "description": "A Graph Visualization Framework in JavaScript", "keywords": [ "antv", @@ -61,7 +61,7 @@ }, "dependencies": { "@antv/g-base": "^0.5.1", - "@antv/g6-core": "0.3.7", + "@antv/g6-core": "4.3.8", "@antv/util": "~2.0.5" }, "devDependencies": { @@ -87,6 +87,6 @@ "ts-jest": "^24.1.0", "ts-loader": "^7.0.3", "typescript": "^3.9.5", - "@antv/g6": "4.3.7" + "@antv/g6": "4.3.8" } } \ No newline at end of file diff --git a/packages/g6/package.json b/packages/g6/package.json index 43086f8e078..51383a2af92 100644 --- a/packages/g6/package.json +++ b/packages/g6/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g6", - "version": "4.3.7", + "version": "4.3.8", "description": "A Graph Visualization Framework in JavaScript", "keywords": [ "antv", @@ -66,7 +66,7 @@ ] }, "dependencies": { - "@antv/g6-pc": "0.3.7" + "@antv/g6-pc": "4.3.8" }, "devDependencies": { "@babel/core": "^7.7.7", diff --git a/packages/g6/src/index.ts b/packages/g6/src/index.ts index 151380f1020..4f23d0da298 100644 --- a/packages/g6/src/index.ts +++ b/packages/g6/src/index.ts @@ -1,7 +1,7 @@ import G6 from '@antv/g6-pc'; -G6.version = '4.3.7'; +G6.version = '4.3.8'; export * from '@antv/g6-pc'; export default G6; -export const version = '4.3.7'; +export const version = '4.3.8'; diff --git a/packages/pc/package.json b/packages/pc/package.json index e60ab6ca04b..7d98915136c 100644 --- a/packages/pc/package.json +++ b/packages/pc/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g6-pc", - "version": "0.3.7", + "version": "0.3.8", "description": "A Graph Visualization Framework in JavaScript", "keywords": [ "antv", @@ -74,9 +74,9 @@ "@antv/g-canvas": "^0.5.2", "@antv/g-math": "^0.1.1", "@antv/g-svg": "^0.5.1", - "@antv/g6-core": "0.3.7", - "@antv/g6-plugin": "0.3.7", - "@antv/g6-element": "0.3.7", + "@antv/g6-core": "0.3.8", + "@antv/g6-plugin": "0.3.8", + "@antv/g6-element": "0.3.8", "@antv/algorithm": "^0.1.8", "@antv/hierarchy": "^0.6.7", "@antv/layout": "^0.1.14", diff --git a/packages/pc/src/behavior/drag-combo.ts b/packages/pc/src/behavior/drag-combo.ts index db36e903778..663969557c6 100644 --- a/packages/pc/src/behavior/drag-combo.ts +++ b/packages/pc/src/behavior/drag-combo.ts @@ -77,6 +77,8 @@ export default { const graph: IGraph = this.graph; const { item } = evt; + this.currentShouldEnd = true; + if (!this.validationCombo(evt)) return; this.targets = []; @@ -185,11 +187,11 @@ export default { } }, - updatePositions(evt: IG6GraphEvent) { + updatePositions(evt: IG6GraphEvent, restore: boolean) { // 当启用 delegate 时,拖动结束时需要更新 combo - if (this.enableDelegate) { + if (this.enableDelegate || restore) { each(this.targets, (item) => { - this.updateCombo(item, evt); + this.updateCombo(item, evt, restore); }); } }, @@ -197,10 +199,9 @@ export default { onDrop(evt: IG6GraphEvent) { // 被放下的目标 combo const { item } = evt; - if (!item || !this.targets || item.destroyed) { - return; - } - this.updatePositions(evt); + this.currentShouldEnd = this.shouldEnd.call(this, evt, item); + this.updatePositions(evt, !this.currentShouldEnd); + if (!this.currentShouldEnd || !item || !this.targets || item.destroyed) return; const graph: IGraph = this.graph; @@ -230,11 +231,16 @@ export default { }, onNodeDrop(evt: IG6GraphEvent) { if (!this.targets || this.targets.length === 0) return; - this.updatePositions(evt); const graph: IGraph = this.graph; const item = evt.item as INode; const comboId = item.getModel().comboId as string; + + const newParentCombo = comboId ? graph.findById(comboId) : undefined; + this.currentShouldEnd = this.shouldEnd.call(this, evt, newParentCombo); + this.updatePositions(evt, !this.currentShouldEnd); + if (!this.currentShouldEnd) return; + let droppedCombo; // 如果被放置的的节点有 comboId,且这个 comboId 与正在被拖拽的 combo 的父 id 不相同,则更新父亲为 comboId if (comboId) { @@ -299,7 +305,9 @@ export default { onDragEnd(evt: IG6GraphEvent) { if (!this.targets || this.targets.length === 0) return; const item = evt.item; - this.updatePositions(evt); + if (this.currentShouldEnd) { + this.updatePositions(evt); + } const parentCombo = this.getParentCombo(item.getModel().parentId); const graph: IGraph = this.graph; if (parentCombo && this.activeState) { @@ -363,12 +371,12 @@ export default { } }, - updateCombo(item: ICombo, evt: IG6GraphEvent) { + updateCombo(item: ICombo, evt: IG6GraphEvent, restore: boolean) { this.traverse(item, (param) => { if (param.destroyed) { return false; } - this.updateSignleItem(param, evt); + this.updateSignleItem(param, evt, restore); return true; }); }, @@ -378,7 +386,7 @@ export default { * @param item 当前正在拖动的元素 * @param evt */ - updateSignleItem(item: Item, evt: IG6GraphEvent) { + updateSignleItem(item: Item, evt: IG6GraphEvent, restore: boolean) { const { origin } = this; const graph: IGraph = this.graph; const model = item.getModel() as ComboConfig; @@ -391,8 +399,13 @@ export default { }; } - const x: number = evt.x - origin.x + this.point[itemId].x; - const y: number = evt.y - origin.y + this.point[itemId].y; + let x: number = evt.x - origin.x + this.point[itemId].x; + let y: number = evt.y - origin.y + this.point[itemId].y; + + if (restore) { + x += origin.x - evt.x; + y += origin.y - evt.y; + } graph.updateItem(item, { x, y }); }, @@ -444,6 +457,7 @@ export default { }, name: 'combo-delegate-shape', }); + this.delegateShape.set('capture', false); this.delegate = this.delegateShape; } else { const clientX = evt.x - this.origin.x + this.originPoint.minX; diff --git a/packages/pc/src/behavior/drag-node.ts b/packages/pc/src/behavior/drag-node.ts index 572c23fdc66..bcc43d7d63e 100644 --- a/packages/pc/src/behavior/drag-node.ts +++ b/packages/pc/src/behavior/drag-node.ts @@ -95,6 +95,7 @@ export default { * @param evt */ onDragStart(evt: IG6GraphEvent) { + this.currentShouldEnd = true; if (!this.shouldBegin.call(this, evt)) { return; } @@ -214,7 +215,7 @@ export default { * @param evt */ onDragEnd(evt: IG6GraphEvent) { - if (!this.origin || !this.shouldEnd.call(this, evt)) { + if (!this.origin) { return; } @@ -230,7 +231,6 @@ export default { this.delegateRect = null; } - this.updatePositions(evt); if (this.get('updateEdge') && this.enableOptimize && !this.enableDelegate) { this.targets.forEach(node => { const edges = node.getEdges(); @@ -288,10 +288,10 @@ export default { */ onDropCombo(evt: IG6GraphEvent) { const item = evt.item as ICombo; - if (!this.validationCombo(item)) return; - - this.updatePositions(evt); - + this.currentShouldEnd = this.shouldEnd.call(this, evt, item); + // 若不允许结束,则将节点位置设置回初识位置。后面的逻辑仍需要执行 + this.updatePositions(evt, !this.currentShouldEnd); + if (!this.currentShouldEnd || !this.validationCombo(item)) return; const graph: IGraph = this.graph; if (this.comboActiveState) { @@ -324,8 +324,10 @@ export default { onDropCanvas(evt: IG6GraphEvent) { const graph: IGraph = this.graph; - if (!this.targets || this.targets.length === 0) return; - this.updatePositions(evt); + this.currentShouldEnd = this.shouldEnd.call(this, evt, undefined); + // 若不允许结束,则将节点位置设置回初识位置。后面的逻辑仍需要执行 + this.updatePositions(evt, !this.currentShouldEnd); + if (!this.targets || this.targets.length === 0 || !this.currentShouldEnd) return; if (this.onlyChangeComboSize) { // 拖动节点结束后,动态改变 Combo 的大小 graph.updateCombos(); @@ -348,11 +350,16 @@ export default { if (!this.targets || this.targets.length === 0) return; const self = this; const item = evt.item as INode; - this.updatePositions(evt); const graph: IGraph = self.graph; const comboId = item.getModel().comboId as string; + const newParentCombo = comboId ? graph.findById(comboId) : undefined; + this.currentShouldEnd = this.shouldEnd.call(this, evt, newParentCombo); + // 若不允许结束,则将节点位置设置回初识位置。后面的逻辑仍需要执行 + this.updatePositions(evt, !this.currentShouldEnd); + if (!this.currentShouldEnd) return; + if (this.onlyChangeComboSize) { graph.updateCombos(); } else if (comboId) { @@ -409,7 +416,7 @@ export default { } }, - updatePositions(evt: IG6GraphEvent) { + updatePositions(evt: IG6GraphEvent, restore: boolean) { if (!this.targets || this.targets.length === 0) return; // 当开启 delegate 时,拖动结束后需要更新所有已选中节点的位置 if (this.get('enableDelegate')) { @@ -423,15 +430,15 @@ export default { updateEdge: this.get('updateEdge'), updateFunc: this.update, }); - else this.targets.map(node => this.update(node, evt)); - } + else if (!restore) this.targets.map(node => this.update(node, evt)); + } else this.targets.map(node => this.update(node, evt, restore)); }, /** * 更新节点 * @param item 拖动的节点实例 * @param evt */ - update(item: Item, evt: IG6GraphEvent) { + update(item: Item, evt: IG6GraphEvent, restore: boolean) { const { origin } = this; const model: NodeConfig = item.get('model'); const nodeId: string = item.get('id'); @@ -442,8 +449,13 @@ export default { }; } - const x: number = evt.x - origin.x + this.point[nodeId].x; - const y: number = evt.y - origin.y + this.point[nodeId].y; + let x: number = evt.x - origin.x + this.point[nodeId].x; + let y: number = evt.y - origin.y + this.point[nodeId].y; + + if (restore) { + x += origin.x - evt.x; + y += origin.y - evt.y; + } const pos: Point = { x, y }; diff --git a/packages/pc/src/global.ts b/packages/pc/src/global.ts index 0ae371d1a9a..2de8d623530 100644 --- a/packages/pc/src/global.ts +++ b/packages/pc/src/global.ts @@ -7,7 +7,7 @@ const textColor = 'rgb(0, 0, 0)'; const colorSet = getColorsWithSubjectColor(subjectColor, backColor); export default { - version: '0.3.7', + version: '0.3.8', rootContainerClassName: 'root-container', nodeContainerClassName: 'node-container', edgeContainerClassName: 'edge-container', diff --git a/packages/pc/src/graph/controller/layout.ts b/packages/pc/src/graph/controller/layout.ts index 80fc017a09f..e3a64bbbe5c 100644 --- a/packages/pc/src/graph/controller/layout.ts +++ b/packages/pc/src/graph/controller/layout.ts @@ -29,8 +29,8 @@ const helper = { }, }; -const GPULayoutNames = ['fruchterman', 'gForce']; -const LayoutPipesAdjustNames = ['force', 'grid', 'circular']; +const GPU_LAYOUT_NAMES = ['fruchterman', 'gForce']; +const LAYOUT_PIPES_ADJUST_NAMES = ['force', 'grid', 'circular']; export default class LayoutController extends AbstractLayout { public graph: IGraph; @@ -109,6 +109,7 @@ export default class LayoutController extends AbstractLayout { private execLayoutMethod(layoutCfg, order): Promise { return new Promise(async (reslove, reject) => { const { graph } = this; + if (graph.get('destroyed')) return; let layoutType = layoutCfg.type; // 每个布局方法都需要注册 @@ -226,7 +227,7 @@ export default class LayoutController extends AbstractLayout { graph.emit('beforelayout'); this.initPositions(layoutCfg.center, nodes); - // init hidden ndoes + // init hidden nodes this.initPositions(layoutCfg.center, hiddenNodes); // 防止用户直接用 -gpu 结尾指定布局 @@ -501,7 +502,7 @@ export default class LayoutController extends AbstractLayout { resolve(); } - if (!LayoutPipesAdjustNames.includes(adjust)) { + if (!LAYOUT_PIPES_ADJUST_NAMES.includes(adjust)) { console.warn(`The adjust type ${adjust} is not supported yet, please assign it with 'force', 'grid', or 'circular'.` ); resolve(); } @@ -536,11 +537,7 @@ export default class LayoutController extends AbstractLayout { } public hasGPUVersion(layoutName: string): boolean { - const length = GPULayoutNames.length; - for (let i = 0; i < length; i++) { - if (GPULayoutNames[i] === layoutName) return true; - } - return false; + return GPU_LAYOUT_NAMES.includes(layoutName); } public destroy() { diff --git a/packages/pc/src/graph/graph.ts b/packages/pc/src/graph/graph.ts index d7ed1f799f4..c54a66a6770 100644 --- a/packages/pc/src/graph/graph.ts +++ b/packages/pc/src/graph/graph.ts @@ -161,11 +161,15 @@ export default class Graph extends AbstractGraph implements IGraph { if (watermarker) await this.downloadImageWatermark(watermarker, context, width, height); if (backgroundColor) { const pixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio : 1; - imageData = context.getImageData(0, 0, width * pixelRatio, height * pixelRatio); - compositeOperation = context.globalCompositeOperation; - context.globalCompositeOperation = 'destination-over'; - context.fillStyle = backgroundColor; - context.fillRect(0, 0, width, height); + try { + imageData = context.getImageData(0, 0, width * pixelRatio, height * pixelRatio); + compositeOperation = context.globalCompositeOperation; + context.globalCompositeOperation = 'destination-over'; + context.fillStyle = backgroundColor; + context.fillRect(0, 0, width, height); + } catch (error) { + console.error('Download image failed. Out of memory at ImageData creation'); + } } dataURL = canvasDom.toDataURL(type); if (backgroundColor) { @@ -215,11 +219,15 @@ export default class Graph extends AbstractGraph implements IGraph { let compositeOperation; if (backgroundColor) { const pixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio : 1; - imageData = context.getImageData(0, 0, width * pixelRatio, height * pixelRatio); - compositeOperation = context.globalCompositeOperation; - context.globalCompositeOperation = 'destination-over'; - context.fillStyle = backgroundColor; - context.fillRect(0, 0, width, height); + try { + imageData = context.getImageData(0, 0, width * pixelRatio, height * pixelRatio); + compositeOperation = context.globalCompositeOperation; + context.globalCompositeOperation = 'destination-over'; + context.fillStyle = backgroundColor; + context.fillRect(0, 0, width, height); + } catch (error) { + console.error('Download image failed. Out of memory at ImageData creation'); + } } dataURL = canvasDom.toDataURL(type); if (backgroundColor) { @@ -308,11 +316,15 @@ export default class Graph extends AbstractGraph implements IGraph { let compositeOperation; if (backgroundColor) { const pixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio : 1; - imageData = context.getImageData(0, 0, vWidth * pixelRatio, vHeight * pixelRatio); - compositeOperation = context.globalCompositeOperation; - context.globalCompositeOperation = 'destination-over'; - context.fillStyle = backgroundColor; - context.fillRect(0, 0, vWidth, vHeight); + try { + imageData = context.getImageData(0, 0, vWidth * pixelRatio, vHeight * pixelRatio); + compositeOperation = context.globalCompositeOperation; + context.globalCompositeOperation = 'destination-over'; + context.fillStyle = backgroundColor; + context.fillRect(0, 0, vWidth, vHeight); + } catch (error) { + console.error('Download image failed. Out of memory at ImageData creation'); + } } dataURL = vCanvasEl.toDataURL(type); if (backgroundColor) { @@ -423,6 +435,10 @@ export default class Graph extends AbstractGraph implements IGraph { } private dataURLToImage(dataURL: string, renderer: string, link, fileName) { + if (!dataURL || dataURL === 'data:') { + console.error('Download image failed. The graph is too large or there is invalid attribute values in graph items'); + return; + } if (typeof window !== 'undefined') { if (window.Blob && window.URL && renderer !== 'svg') { const arr = dataURL.split(','); diff --git a/packages/pc/tests/unit/behavior/drag-node-spec.ts b/packages/pc/tests/unit/behavior/drag-node-spec.ts index 66e6bb64423..ddd0c5f62dc 100644 --- a/packages/pc/tests/unit/behavior/drag-node-spec.ts +++ b/packages/pc/tests/unit/behavior/drag-node-spec.ts @@ -46,8 +46,10 @@ describe('drag-node', () => { expect(dragMatrix[6]).toEqual(50); expect(dragMatrix[7]).toEqual(50); + graph.emit('canvas:drop', { x: 120, y: 120, item: node }); graph.emit('node:dragend', { x: 120, y: 120, item: node }); const matrix = node.get('group').getMatrix(); + console.log('matrix',matrix) expect(matrix[0]).toEqual(1); expect(matrix[6]).toEqual(70); expect(matrix[7]).toEqual(70); @@ -91,6 +93,7 @@ describe('drag-node', () => { expect(dragMatrix[6]).toEqual(50); expect(dragMatrix[7]).toEqual(50); + graph.emit('canvas:drop', { x: 120, y: 120, item: node }); graph.emit('touchend', { x: 120, y: 120, item: node }); const matrix = node.get('group').getMatrix(); expect(matrix[0]).toEqual(1); @@ -258,6 +261,7 @@ describe('drag-node', () => { expect(dragMatrix[6]).toEqual(50); expect(dragMatrix[7]).toEqual(50); + graph.emit('canvas:drop', { x: 200, y: 200, item: node0 }); graph.emit('node:dragend', { x: 200, y: 200, item: node0 }); const matrix = node0.get('group').getMatrix(); expect(matrix[0]).toEqual(1); @@ -381,18 +385,21 @@ describe('drag-node', () => { setTimeout(() => { expect(mathEqual(289, path[1][1])).toEqual(true); expect(mathEqual(300, path[1][2])).toEqual(true); + graph.emit('canvas:drop', { x: 140, y: 140, item: source }); graph.emit('node:dragend', { x: 140, y: 140, item: source }); - path = edge - .get('group') - .get('children')[0] - .attr('path'); - expect(path[0][1]).toEqual(97.77817459305203); - expect(path[0][2]).toEqual(97.77817459305203); setTimeout(() => { - expect(mathEqual(289, path[1][1])).toEqual(true); - expect(mathEqual(300, path[1][2])).toEqual(true); - graph.destroy(); - done() + path = edge + .get('group') + .get('children')[0] + .attr('path'); + expect(path[0][1]).toEqual(97.77817459305203); + expect(path[0][2]).toEqual(97.77817459305203); + setTimeout(() => { + expect(mathEqual(289, path[1][1])).toEqual(true); + expect(mathEqual(300, path[1][2])).toEqual(true); + graph.destroy(); + done() + }, 50) }, 50) }, 50) }, 50) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index a3b53daae59..47e4c166f9c 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g6-plugin", - "version": "0.3.7", + "version": "0.3.8", "description": "G6 Plugin", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ "@antv/g-base": "^0.5.1", "@antv/g-canvas": "^0.5.2", "@antv/g-svg": "^0.5.2", - "@antv/g6-core": "0.3.7", + "@antv/g6-core": "4.3.8", "@antv/matrix-util": "^3.0.4", "@antv/scale": "^0.3.4", "@antv/util": "^2.0.9", @@ -57,6 +57,6 @@ "jquery": "^3.5.1", "rimraf": "^3.0.2", "ts-jest": "^26.4.4", - "@antv/g6": "4.3.7" + "@antv/g6": "4.3.8" } } \ No newline at end of file diff --git a/packages/plugin/src/menu/index.ts b/packages/plugin/src/menu/index.ts index 4bad4e2de6a..3a4241565c6 100644 --- a/packages/plugin/src/menu/index.ts +++ b/packages/plugin/src/menu/index.ts @@ -98,7 +98,6 @@ export default class Menu extends Base { protected onMenuShow(e: IG6GraphEvent) { const self = this; e.preventDefault(); - e.stopPropagation(); const itemTypes = this.get('itemTypes'); if (!e.item) { diff --git a/packages/site/docs/api/shapeProperties.en.md b/packages/site/docs/api/shapeProperties.en.md index 27b91802019..e6ab22dfd52 100644 --- a/packages/site/docs/api/shapeProperties.en.md +++ b/packages/site/docs/api/shapeProperties.en.md @@ -458,6 +458,13 @@ group.addShape('text', { }); ``` +### text + + _String_ **optional** + +The text content of the text shape. + + ### textAlign _String_ **optional** diff --git a/packages/site/docs/api/shapeProperties.zh.md b/packages/site/docs/api/shapeProperties.zh.md index d55d8a5367c..6a399047aa2 100644 --- a/packages/site/docs/api/shapeProperties.zh.md +++ b/packages/site/docs/api/shapeProperties.zh.md @@ -460,6 +460,13 @@ group.addShape('text', { }); ``` +### text + + _String_ **optional** + +文本文字内容。 + + ### textAlign _String_ **optional** diff --git a/packages/site/docs/manual/middle/elements/nodes/react-node.zh.md b/packages/site/docs/manual/middle/elements/nodes/react-node.zh.md index f20ef071598..d486d593266 100644 --- a/packages/site/docs/manual/middle/elements/nodes/react-node.zh.md +++ b/packages/site/docs/manual/middle/elements/nodes/react-node.zh.md @@ -1,5 +1,5 @@ --- -title: 使用React直接定义节点 +title: 使用 React 定义节点 order: 5 --- @@ -118,30 +118,30 @@ const Card = ({ cfg }) => { G6.registerNode('test', createNodeFromReact(Card)); ``` -他展示了这样一个卡片的节点: +展示了这样一个卡片的节点: graph ### 使用指南 -#### 图形React组件 +#### 图形 React 组件 -定义React组件节点的时候,你不能使用任何的hook或者异步获取的逻辑,因为目前节点绘制需要是一个同步的过程,并且,我们推荐把所有状态以及数据信息放在节点本身data中,这样可以更方便的进行管理。在React组件节点中,所有的数据流动都应该是:节点数据 -> react组件props(cfg) -> 节点内容变化。组件本身需要是没有任何副作用的,所有对于节点数据的改变,都是基于updateItem的。 +定义 React 组件节点的时候,你不能使用任何的 hook 或者异步获取的逻辑,因为目前节点绘制需要是一个同步的过程,并且,我们推荐把所有状态以及数据信息放在节点本身 data 中,这样可以更方便的进行管理。在React组件节点中,所有的数据流动都应该是:节点数据 -> react 组件 props(cfg) -> 节点内容变化。组件本身需要是没有任何副作用的,所有对于节点数据的改变,都是基于 updateItem 的。 -#### React组件内部的布局 +#### React 组件内部的布局 -如果你没有做任何定位或者布局,所有布局都会按照正常的文档流,自上而下排布。为了让大家有更自由的布局方式,React内部还支持了flex布局,你可以通过操作:`alignContent`,`alignItems`,`alignSelf`,`display`,`flex`,`flexBasis`,`flexGrow`,`flexShrink`,`flexDirection`,`flexWrap`,`height`,`width`,`justifyContent`,`margin`,`padding`,`maxHeight`,`maxWidth`,`minHeight`,`minWidth` 这几个属性来控制节点内部的布局。 +如果你没有做任何定位或者布局,所有布局都会按照正常的文档流,自上而下排布。为了让大家有更自由的布局方式, React 内部还支持了 flex 布局,你可以通过操作:`alignContent`,`alignItems`,`alignSelf`,`display`,`flex`,`flexBasis`,`flexGrow`,`flexShrink`,`flexDirection`,`flexWrap`,`height`,`width`,`justifyContent`,`margin`,`padding`,`maxHeight`,`maxWidth`,`minHeight`,`minWidth` 这几个属性来控制节点内部的布局。 -#### 基于React组件Shape的事件处理 +#### 基于 React 组件 Shape 的事件处理 -为了更加方便的控制节点,我们支持了在节点内部的某一个图形进行事件绑定(事件冒泡会在后续版本支持),这些事件绑定函数都有统一的参数: `(evt: G6本身的事件, node: 事件发生的节点, shape: 事件发生的Shape, graph: 发出事件的graph)`,目前我们支持了大部分的G6事件:`onClick`,`onDBClick `,`onMouseEnter`,`onMouseMove `,`onMouseOut`,`onMouseOver `,`onMouseLeave`,`onMouseDown `,`onMouseUp `,`onDragStart `,`onDrag`,`onDragEnd `,`onDragEnter `,`onDragLeave `,`onDragOver`,`onDrop`,`onContextMenu` +为了更加方便的控制节点,我们支持了在节点内部的某一个图形进行事件绑定(事件冒泡会在后续版本支持),这些事件绑定函数都有统一的参数: `(evt: G6本身的事件, node: 事件发生的节点, shape: 事件发生的Shape, graph: 发出事件的graph)`,目前我们支持了大部分的 G6 事件:`onClick`,`onDBClick `,`onMouseEnter`,`onMouseMove `,`onMouseOut`,`onMouseOver `,`onMouseLeave`,`onMouseDown `,`onMouseUp `,`onDragStart `,`onDrag`,`onDragEnd `,`onDragEnter `,`onDragLeave `,`onDragOver`,`onDrop`,`onContextMenu` -⚠️ 注意: 使用了事件后,需要使用函数 `appenAutoShapeListener(graph)` 对所进行对图进行事件挂载才可以生效,该方法可以直接从`@antv/g6-react-node`包引出。 +⚠️ 注意: 使用了事件后,需要使用函数 `appenAutoShapeListener(graph)` 对所进行对图进行事件挂载才可以生效,该方法可以直接从 `@antv/g6-react-node` 包引出。 -#### 基于React组件Shape的简单动画(alpha) +#### 基于 React 组件 Shape 的简单动画(alpha) -为了更加方便给节点添加动画,所以我们内置了一些简单的动画来使用,希望能满足基本交互的效果,第一期我们暂时只推出了六种动画,`animation`属性设置后就有动画,属性为空则停止动画。 +为了更加方便给节点添加动画,所以我们内置了一些简单的动画来使用,希望能满足基本交互的效果,第一期我们暂时只推出了六种动画, `animation` 属性设置后就有动画,属性为空则停止动画。 示例: diff --git a/packages/site/docs/manual/middle/states/defaultBehavior.en.md b/packages/site/docs/manual/middle/states/defaultBehavior.en.md index 549a26db395..e00fd3b8361 100644 --- a/packages/site/docs/manual/middle/states/defaultBehavior.en.md +++ b/packages/site/docs/manual/middle/states/defaultBehavior.en.md @@ -23,7 +23,8 @@ Supported by V3.5 or later versions. - `onlyChangeComboSize`: Supported by V3.5 or later vertions. Only Change the size of the prarent combo whose child combo to be dragged, which means do not change the hierarchy structures of combos and nodes. `false` by default; - `activeState`: The state's name(string) of the entered combo to be dragged over, coordinating with the configuration in `comboStateStyles` to define the state styles when instantiating a graph. It is empty by default; - `selectedState`: The state's name(string) when combo is selected, `'selected'` by default; - - `shouldUpdate(e)`: Whether allow the behavior happens on the current item (e.item), see the example below for detail. + - `shouldUpdate(e)`: Whether allow the behavior happens on the current item (e.item), see the example below for detail; + - `shouldEnd(e, newParent)`: 【supported by v4.3.8 and later versions】Whether allow the behavior ends with current item (e.item) and the new parent combo. the second parameter is the detected new parent when drop. If it is dropped on the canvas, `newParent` is `undefined`, see the example below for detail. **Using Default Configuration** @@ -50,6 +51,12 @@ const graph = new G6.Graph({ if (e.item && e.item.getModel().id === 'combo1') return false; return true; }, + // shouldEnd【supported by v4.3.8 and later versions】 + shouldEnd: (e, newParent) => { + // The combos are not allow to be drop on the combo with id combo1 + if (newParent && newParent.getModel().id === 'combo1') return false; + return true; + } }, ], }, diff --git a/packages/site/docs/manual/middle/states/defaultBehavior.zh.md b/packages/site/docs/manual/middle/states/defaultBehavior.zh.md index cf030ed97c8..aa2b5751b85 100644 --- a/packages/site/docs/manual/middle/states/defaultBehavior.zh.md +++ b/packages/site/docs/manual/middle/states/defaultBehavior.zh.md @@ -23,7 +23,8 @@ V3.5 以上版本支持。 - `onlyChangeComboSize`:拖动嵌套的 Combo 时,只改变父 Combo 的大小,不改变层级关系,默认为 false; - `activeState`:当拖动 Combo 时,父 Combo 或进入到的 Combo 的状态值,需要用户在实例化 Graph 时在 `comboStateStyles` 里面配置,默认为空; - `selectedState`:选中 Combo 的状态,默认为 selected,需要在 `comboStateStyles` 里面配置; - - `shouldUpdate(e)`:是否允许当前被操作的 combo 被拖拽,参见下面示例。 + - `shouldUpdate(e)`:是否允许当前被操作的 combo 被拖拽,参见下面示例; + - `shouldEnd(e, newParent)`:【v4.3.8 后支持】是否允许当前被操作的 combo 完成拖拽。第二个参数为拖拽释放时检测到的新父 combo,若释放在画布上,则 `newParent` 为 `undefined`,参见下面示例。 **使用默认配置** @@ -50,6 +51,12 @@ const graph = new G6.Graph({ if (e.item && e.item.getModel().id === 'combo1') return false; return true; }, + // shouldEnd【v4.3.8 后支持】 + shouldEnd: (e, newParent) => { + // 不可以将 combo 释放到 combo1 上 + if (newParent && newParent.getModel().id === 'combo1') return false; + return true; + } }, ], }, diff --git a/packages/site/package.json b/packages/site/package.json index a1a4ede82cf..0323ad5895e 100644 --- a/packages/site/package.json +++ b/packages/site/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@antv/g6-site", - "version": "4.3.7", + "version": "4.3.8", "description": "G6 sites deployed on gh-pages", "keywords": [ "antv", @@ -36,7 +36,7 @@ "dependencies": { "@ant-design/icons": "^4.0.6", "@antv/chart-node-g6": "^0.0.3", - "@antv/g6": "4.3.7", + "@antv/g6": "4.3.8", "@antv/gatsby-theme-antv": "1.1.1", "@antv/util": "^2.0.9", "@antv/vis-predict-engine": "^0.1.1",