mirror of
https://gitee.com/antv/g6.git
synced 2024-12-03 04:08:32 +08:00
feat: tree formatted data rendering; feat: collapse-expand-tree behavior;
This commit is contained in:
parent
11a9a3016a
commit
5ebc32f86c
@ -46,7 +46,7 @@
|
|||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:integration": "node --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict node_modules/jest/bin/jest tests/integration/ --config jest.node.config.js --coverage -i --logHeapUsage --detectOpenHandles",
|
"test:integration": "node --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict node_modules/jest/bin/jest tests/integration/ --config jest.node.config.js --coverage -i --logHeapUsage --detectOpenHandles",
|
||||||
"size": "limit-size",
|
"size": "limit-size",
|
||||||
"test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/edge-spec.ts",
|
"test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/item-animate-spec.ts",
|
||||||
"test-behavior": "DEBUG_MODE=1 jest --watch ./tests/unit/item-3d-spec.ts"
|
"test-behavior": "DEBUG_MODE=1 jest --watch ./tests/unit/item-3d-spec.ts"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
@ -58,7 +58,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/colors": "^7.0.0",
|
"@ant-design/colors": "^7.0.0",
|
||||||
"@antv/algorithm": "^0.1.25",
|
"@antv/algorithm": "^0.1.26",
|
||||||
"@antv/dom-util": "^2.0.4",
|
"@antv/dom-util": "^2.0.4",
|
||||||
"@antv/g": "^5.15.7",
|
"@antv/g": "^5.15.7",
|
||||||
"@antv/g-canvas": "^1.9.28",
|
"@antv/g-canvas": "^1.9.28",
|
||||||
@ -75,6 +75,7 @@
|
|||||||
"@antv/matrix-util": "^3.0.4",
|
"@antv/matrix-util": "^3.0.4",
|
||||||
"@antv/util": "~2.0.5",
|
"@antv/util": "~2.0.5",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
|
"stats-js": "^1.0.1",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.5.0",
|
||||||
"typedoc-plugin-markdown": "^3.14.0",
|
"typedoc-plugin-markdown": "^3.14.0",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
@ -115,6 +116,7 @@
|
|||||||
"rollup-plugin-polyfill-node": "^0.8.0",
|
"rollup-plugin-polyfill-node": "^0.8.0",
|
||||||
"rollup-plugin-typescript": "^1.0.1",
|
"rollup-plugin-typescript": "^1.0.1",
|
||||||
"rollup-plugin-visualizer": "^5.6.0",
|
"rollup-plugin-visualizer": "^5.6.0",
|
||||||
|
"stats-js": "1.0.1",
|
||||||
"stats.js": "^0.17.0",
|
"stats.js": "^0.17.0",
|
||||||
"ts-jest": "^28.0.8",
|
"ts-jest": "^28.0.8",
|
||||||
"typedoc": "^0.24.0",
|
"typedoc": "^0.24.0",
|
||||||
|
@ -74,6 +74,7 @@ export default class Combo extends Node {
|
|||||||
displayModel: ComboDisplayModel,
|
displayModel: ComboDisplayModel,
|
||||||
diffData?: { previous: ComboUserModelData; current: ComboUserModelData },
|
diffData?: { previous: ComboUserModelData; current: ComboUserModelData },
|
||||||
diffState?: { previous: State[]; current: State[] },
|
diffState?: { previous: State[]; current: State[] },
|
||||||
|
animate: boolean = true,
|
||||||
onfinish: Function = () => {},
|
onfinish: Function = () => {},
|
||||||
) {
|
) {
|
||||||
if (displayModel.data.collapsed) {
|
if (displayModel.data.collapsed) {
|
||||||
@ -90,7 +91,7 @@ export default class Combo extends Node {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
super.draw(displayModel, diffData, diffState, onfinish);
|
super.draw(displayModel, diffData, diffState, animate, onfinish);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,7 @@ import { animateShapes } from '../util/animate';
|
|||||||
import { EdgeStyleSet } from '../types/theme';
|
import { EdgeStyleSet } from '../types/theme';
|
||||||
import Item from './item';
|
import Item from './item';
|
||||||
import Node from './node';
|
import Node from './node';
|
||||||
|
import Combo from './combo';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
model: EdgeModel;
|
model: EdgeModel;
|
||||||
@ -50,6 +51,7 @@ export default class Edge extends Item {
|
|||||||
displayModel: EdgeDisplayModel,
|
displayModel: EdgeDisplayModel,
|
||||||
diffData?: { previous: EdgeModelData; current: EdgeModelData },
|
diffData?: { previous: EdgeModelData; current: EdgeModelData },
|
||||||
diffState?: { previous: State[]; current: State[] },
|
diffState?: { previous: State[]; current: State[] },
|
||||||
|
animate: boolean = true,
|
||||||
onfinish: Function = () => {},
|
onfinish: Function = () => {},
|
||||||
) {
|
) {
|
||||||
// get the end points
|
// get the end points
|
||||||
@ -94,7 +96,7 @@ export default class Edge extends Item {
|
|||||||
|
|
||||||
const timing = firstRendering ? 'buildIn' : 'update';
|
const timing = firstRendering ? 'buildIn' : 'update';
|
||||||
// handle shape's animate
|
// handle shape's animate
|
||||||
if (!disableAnimate && usingAnimates[timing]?.length) {
|
if (animate && !disableAnimate && usingAnimates[timing]?.length) {
|
||||||
this.animations = animateShapes(
|
this.animations = animateShapes(
|
||||||
usingAnimates,
|
usingAnimates,
|
||||||
targetStyles, // targetStylesMap
|
targetStyles, // targetStylesMap
|
||||||
@ -103,7 +105,7 @@ export default class Edge extends Item {
|
|||||||
firstRendering ? 'buildIn' : 'update',
|
firstRendering ? 'buildIn' : 'update',
|
||||||
this.changedStates,
|
this.changedStates,
|
||||||
this.animateFrameListener,
|
this.animateFrameListener,
|
||||||
() => onfinish(displayModel.id),
|
(canceled) => onfinish(displayModel.id, canceled),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,8 +142,8 @@ export default class Edge extends Item {
|
|||||||
|
|
||||||
public clone(
|
public clone(
|
||||||
containerGroup: Group,
|
containerGroup: Group,
|
||||||
sourceItem: Node,
|
sourceItem: Node | Combo,
|
||||||
targetItem: Node,
|
targetItem: Node | Combo,
|
||||||
onlyKeyShape?: boolean,
|
onlyKeyShape?: boolean,
|
||||||
disableAnimate?: boolean,
|
disableAnimate?: boolean,
|
||||||
) {
|
) {
|
||||||
|
@ -68,8 +68,10 @@ export default abstract class Item implements IItem {
|
|||||||
/** The flag of transient item. */
|
/** The flag of transient item. */
|
||||||
public transient = false;
|
public transient = false;
|
||||||
public renderExtensions: any; // TODO
|
public renderExtensions: any; // TODO
|
||||||
/** Cache the animation instances to stop at next lifecycle. */
|
/** Cache the shape animation instances to stop at next lifecycle. */
|
||||||
public animations: IAnimation[];
|
public animations: IAnimation[];
|
||||||
|
/** Cache the group animation instances to stop at next lifecycle. */
|
||||||
|
public groupAnimations: IAnimation[];
|
||||||
|
|
||||||
public themeStyles: {
|
public themeStyles: {
|
||||||
default: ItemShapeStyles;
|
default: ItemShapeStyles;
|
||||||
@ -159,6 +161,7 @@ export default abstract class Item implements IItem {
|
|||||||
displayModel: ItemDisplayModel,
|
displayModel: ItemDisplayModel,
|
||||||
diffData?: { previous: ItemModelData; current: ItemModelData },
|
diffData?: { previous: ItemModelData; current: ItemModelData },
|
||||||
diffState?: { previous: State[]; current: State[] },
|
diffState?: { previous: State[]; current: State[] },
|
||||||
|
animate: boolean = true,
|
||||||
onfinish: Function = () => {},
|
onfinish: Function = () => {},
|
||||||
) {
|
) {
|
||||||
// call this.renderExt.draw in extend implementations
|
// call this.renderExt.draw in extend implementations
|
||||||
@ -198,6 +201,7 @@ export default abstract class Item implements IItem {
|
|||||||
lodStrategy: LodStrategyObj;
|
lodStrategy: LodStrategyObj;
|
||||||
},
|
},
|
||||||
onlyMove?: boolean,
|
onlyMove?: boolean,
|
||||||
|
animate: boolean = true,
|
||||||
onfinish?: Function,
|
onfinish?: Function,
|
||||||
) {
|
) {
|
||||||
// 1. merge model into this model
|
// 1. merge model into this model
|
||||||
@ -218,7 +222,7 @@ export default abstract class Item implements IItem {
|
|||||||
: itemTheme?.lodStrategy || this.lodStrategy;
|
: itemTheme?.lodStrategy || this.lodStrategy;
|
||||||
|
|
||||||
if (onlyMove) {
|
if (onlyMove) {
|
||||||
this.updatePosition(displayModel, diffData, onfinish);
|
this.updatePosition(displayModel, diffData, animate, onfinish);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,9 +246,9 @@ export default abstract class Item implements IItem {
|
|||||||
}
|
}
|
||||||
// 3. call element update fn from useLib
|
// 3. call element update fn from useLib
|
||||||
if (this.states?.length) {
|
if (this.states?.length) {
|
||||||
this.drawWithStates(this.states, onfinish);
|
this.drawWithStates(this.states, animate, onfinish);
|
||||||
} else {
|
} else {
|
||||||
this.draw(this.displayModel, diffData, undefined, onfinish);
|
this.draw(this.displayModel, diffData, undefined, animate, onfinish);
|
||||||
}
|
}
|
||||||
// 4. tag all the states with 'dirty', for state style regenerating when state changed
|
// 4. tag all the states with 'dirty', for state style regenerating when state changed
|
||||||
this.stateDirtyMap = {};
|
this.stateDirtyMap = {};
|
||||||
@ -261,6 +265,7 @@ export default abstract class Item implements IItem {
|
|||||||
public updatePosition(
|
public updatePosition(
|
||||||
displayModel: ItemDisplayModel,
|
displayModel: ItemDisplayModel,
|
||||||
diffData?: { previous: ItemModelData; current: ItemModelData },
|
diffData?: { previous: ItemModelData; current: ItemModelData },
|
||||||
|
animate?: boolean,
|
||||||
onfinish?: Function,
|
onfinish?: Function,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -395,60 +400,63 @@ export default abstract class Item implements IItem {
|
|||||||
|
|
||||||
/** Show the item. */
|
/** Show the item. */
|
||||||
public show(animate = true) {
|
public show(animate = true) {
|
||||||
// TODO: utilize graphcore's view
|
Promise.all(this.stopAnimations()).finally(() => {
|
||||||
this.stopAnimations();
|
if (this.destroyed || this.visible) return;
|
||||||
|
const { animates = {} } = this.displayModel.data;
|
||||||
const { animates = {} } = this.displayModel.data;
|
if (animate && animates.show?.length) {
|
||||||
if (animate && animates.show?.length) {
|
const showAnimateFieldsMap: any = {};
|
||||||
const showAnimateFieldsMap: any = {};
|
Object.values(animates.show).forEach((animate) => {
|
||||||
Object.values(animates.show).forEach((animate) => {
|
const { shapeId = 'group' } = animate;
|
||||||
const { shapeId = 'group' } = animate;
|
showAnimateFieldsMap[shapeId] = (
|
||||||
showAnimateFieldsMap[shapeId] = (
|
showAnimateFieldsMap[shapeId] || []
|
||||||
showAnimateFieldsMap[shapeId] || []
|
).concat(animate.fields);
|
||||||
).concat(animate.fields);
|
});
|
||||||
});
|
const targetStyleMap = {};
|
||||||
const targetStyleMap = {};
|
Object.keys(this.shapeMap).forEach((id) => {
|
||||||
Object.keys(this.shapeMap).forEach((id) => {
|
const shape = this.shapeMap[id];
|
||||||
const shape = this.shapeMap[id];
|
if (!this.cacheHiddenShape[id]) {
|
||||||
if (!this.cacheHiddenShape[id]) {
|
// set the animate fields to initial value
|
||||||
// set the animate fields to initial value
|
if (showAnimateFieldsMap[id]) {
|
||||||
if (showAnimateFieldsMap[id]) {
|
targetStyleMap[id] = targetStyleMap[id] || {};
|
||||||
targetStyleMap[id] = targetStyleMap[id] || {};
|
const beginStyle = getShapeAnimateBeginStyles(shape);
|
||||||
const beginStyle = getShapeAnimateBeginStyles(shape);
|
showAnimateFieldsMap[id].forEach((field) => {
|
||||||
showAnimateFieldsMap[id].forEach((field) => {
|
if (beginStyle.hasOwnProperty(field)) {
|
||||||
if (beginStyle.hasOwnProperty(field)) {
|
targetStyleMap[id][field] = shape.style[field];
|
||||||
targetStyleMap[id][field] = shape.style[field];
|
shape.style[field] = beginStyle[field];
|
||||||
shape.style[field] = beginStyle[field];
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
shape.show();
|
||||||
}
|
}
|
||||||
shape.show();
|
});
|
||||||
|
if (showAnimateFieldsMap.group) {
|
||||||
|
showAnimateFieldsMap.group.forEach((field) => {
|
||||||
|
const usingField = field === 'size' ? 'transform' : field;
|
||||||
|
if (GROUP_ANIMATE_STYLES[0].hasOwnProperty(usingField)) {
|
||||||
|
this.group.style[usingField] =
|
||||||
|
GROUP_ANIMATE_STYLES[0][usingField];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (showAnimateFieldsMap.group) {
|
this.animations = this.runWithAnimates(
|
||||||
showAnimateFieldsMap.group.forEach((field) => {
|
animates,
|
||||||
const usingField = field === 'size' ? 'transform' : field;
|
'show',
|
||||||
if (GROUP_ANIMATE_STYLES[0].hasOwnProperty(usingField)) {
|
targetStyleMap,
|
||||||
this.group.style[usingField] = GROUP_ANIMATE_STYLES[0][usingField];
|
);
|
||||||
}
|
} else {
|
||||||
|
Object.keys(this.shapeMap).forEach((id) => {
|
||||||
|
const shape = this.shapeMap[id];
|
||||||
|
if (!this.cacheHiddenShape[id]) shape.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.animations = this.runWithAnimates(animates, 'show', targetStyleMap);
|
this.visible = true;
|
||||||
} else {
|
});
|
||||||
Object.keys(this.shapeMap).forEach((id) => {
|
|
||||||
const shape = this.shapeMap[id];
|
|
||||||
if (!this.cacheHiddenShape[id]) shape.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.visible = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Hides the item. */
|
/** Hides the item. */
|
||||||
public hide(animate = true) {
|
public hide(animate = true) {
|
||||||
// TODO: utilize graphcore's view
|
|
||||||
this.stopAnimations();
|
|
||||||
const func = () => {
|
const func = () => {
|
||||||
Object.keys(this.shapeMap).forEach((id) => {
|
Object.keys(this.shapeMap).forEach((id) => {
|
||||||
const shape = this.shapeMap[id];
|
const shape = this.shapeMap[id];
|
||||||
@ -457,15 +465,22 @@ export default abstract class Item implements IItem {
|
|||||||
shape.hide();
|
shape.hide();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const { animates = {} } = this.displayModel.data;
|
Promise.all(this.stopAnimations()).then(() => {
|
||||||
if (animate && animates.hide?.length) {
|
if (this.destroyed || !this.visible) return;
|
||||||
this.animations = this.runWithAnimates(animates, 'hide', undefined, func);
|
const { animates = {} } = this.displayModel.data;
|
||||||
} else {
|
if (animate && animates.hide?.length) {
|
||||||
// 2. clear group and remove group
|
this.animations = this.runWithAnimates(
|
||||||
func();
|
animates,
|
||||||
}
|
'hide',
|
||||||
|
undefined,
|
||||||
this.visible = false;
|
func,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 2. clear group and remove group
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
this.visible = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the visibility of the item. */
|
/** Returns the visibility of the item. */
|
||||||
@ -606,7 +621,11 @@ export default abstract class Item implements IItem {
|
|||||||
* @param previousStates previous states
|
* @param previousStates previous states
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private drawWithStates(previousStates: State[], onfinish?: Function) {
|
private drawWithStates(
|
||||||
|
previousStates: State[],
|
||||||
|
animate: boolean = true,
|
||||||
|
onfinish?: Function,
|
||||||
|
) {
|
||||||
const { default: _, ...themeStateStyles } = this.themeStyles;
|
const { default: _, ...themeStateStyles } = this.themeStyles;
|
||||||
const { data: displayModelData } = this.displayModel;
|
const { data: displayModelData } = this.displayModel;
|
||||||
let styles = {}; // merged styles
|
let styles = {}; // merged styles
|
||||||
@ -675,6 +694,7 @@ export default abstract class Item implements IItem {
|
|||||||
previous: previousStates,
|
previous: previousStates,
|
||||||
current: this.states,
|
current: this.states,
|
||||||
},
|
},
|
||||||
|
animate,
|
||||||
onfinish,
|
onfinish,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -729,8 +749,27 @@ export default abstract class Item implements IItem {
|
|||||||
* Stop all the animations on the item.
|
* Stop all the animations on the item.
|
||||||
*/
|
*/
|
||||||
public stopAnimations() {
|
public stopAnimations() {
|
||||||
this.animations?.forEach(stopAnimate);
|
let promises = [];
|
||||||
this.animations = [];
|
if (this.animations?.length) {
|
||||||
|
while (this.animations.length) {
|
||||||
|
const animate = this.animations.pop();
|
||||||
|
if (animate.playState !== 'running') break;
|
||||||
|
promises.push(stopAnimate(animate));
|
||||||
|
// @ts-ignore
|
||||||
|
animate.onManualCancel?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.groupAnimations?.length) {
|
||||||
|
while (this.groupAnimations.length) {
|
||||||
|
const groupAnimate = this.groupAnimations.pop();
|
||||||
|
if (groupAnimate.playState !== 'running') break;
|
||||||
|
promises.push(stopAnimate(groupAnimate));
|
||||||
|
// @ts-ignore
|
||||||
|
groupAnimate.onManualCancel?.();
|
||||||
|
}
|
||||||
|
this.groupAnimations = [];
|
||||||
|
}
|
||||||
|
return promises;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,6 +45,7 @@ export default class Node extends Item {
|
|||||||
this.displayModel as NodeDisplayModel | ComboDisplayModel,
|
this.displayModel as NodeDisplayModel | ComboDisplayModel,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
|
!this.displayModel.data.disableAnimate,
|
||||||
props.onfinish,
|
props.onfinish,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -55,6 +56,7 @@ export default class Node extends Item {
|
|||||||
current: NodeModelData | ComboModelData;
|
current: NodeModelData | ComboModelData;
|
||||||
},
|
},
|
||||||
diffState?: { previous: State[]; current: State[] },
|
diffState?: { previous: State[]; current: State[] },
|
||||||
|
animate: boolean = true,
|
||||||
onfinish: Function = () => {},
|
onfinish: Function = () => {},
|
||||||
) {
|
) {
|
||||||
const { group, renderExt, shapeMap: prevShapeMap, model } = this;
|
const { group, renderExt, shapeMap: prevShapeMap, model } = this;
|
||||||
@ -78,13 +80,13 @@ export default class Node extends Item {
|
|||||||
} else {
|
} else {
|
||||||
// terminate previous animations
|
// terminate previous animations
|
||||||
this.stopAnimations();
|
this.stopAnimations();
|
||||||
this.updatePosition(displayModel, diffData, onfinish);
|
this.updatePosition(displayModel, diffData, animate, onfinish);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { haloShape } = this.shapeMap;
|
const { haloShape } = this.shapeMap;
|
||||||
haloShape?.toBack();
|
haloShape?.toBack();
|
||||||
|
|
||||||
super.draw(displayModel, diffData, diffState, onfinish);
|
super.draw(displayModel, diffData, diffState, animate, onfinish);
|
||||||
this.anchorPointsCache = undefined;
|
this.anchorPointsCache = undefined;
|
||||||
renderExt.updateCache(this.shapeMap);
|
renderExt.updateCache(this.shapeMap);
|
||||||
|
|
||||||
@ -94,7 +96,7 @@ export default class Node extends Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle shape's and group's animate
|
// handle shape's and group's animate
|
||||||
if (!disableAnimate && animates) {
|
if (animate && !disableAnimate && animates) {
|
||||||
const animatesExcludePosition = getAnimatesExcludePosition(animates);
|
const animatesExcludePosition = getAnimatesExcludePosition(animates);
|
||||||
this.animations = animateShapes(
|
this.animations = animateShapes(
|
||||||
animatesExcludePosition, // animates
|
animatesExcludePosition, // animates
|
||||||
@ -104,7 +106,7 @@ export default class Node extends Item {
|
|||||||
firstRendering ? 'buildIn' : 'update',
|
firstRendering ? 'buildIn' : 'update',
|
||||||
this.changedStates,
|
this.changedStates,
|
||||||
this.animateFrameListener,
|
this.animateFrameListener,
|
||||||
() => onfinish(model.id),
|
(canceled) => onfinish(model.id, canceled),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,9 +123,18 @@ export default class Node extends Item {
|
|||||||
lodStrategy: LodStrategyObj;
|
lodStrategy: LodStrategyObj;
|
||||||
},
|
},
|
||||||
onlyMove?: boolean,
|
onlyMove?: boolean,
|
||||||
|
animate?: boolean,
|
||||||
onfinish?: Function,
|
onfinish?: Function,
|
||||||
) {
|
) {
|
||||||
super.update(model, diffData, isReplace, theme, onlyMove, onfinish);
|
super.update(
|
||||||
|
model,
|
||||||
|
diffData,
|
||||||
|
isReplace,
|
||||||
|
theme,
|
||||||
|
onlyMove,
|
||||||
|
animate,
|
||||||
|
onfinish,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,19 +147,20 @@ export default class Node extends Item {
|
|||||||
previous: NodeModelData | ComboModelData;
|
previous: NodeModelData | ComboModelData;
|
||||||
current: NodeModelData | ComboModelData;
|
current: NodeModelData | ComboModelData;
|
||||||
},
|
},
|
||||||
|
animate?: boolean,
|
||||||
onfinish: Function = () => {},
|
onfinish: Function = () => {},
|
||||||
) {
|
) {
|
||||||
const { group } = this;
|
const { group } = this;
|
||||||
const { x, y, z = 0, animates, disableAnimate } = displayModel.data;
|
const { x, y, z = 0, animates, disableAnimate } = displayModel.data;
|
||||||
if (isNaN(x as number) || isNaN(y as number) || isNaN(z)) return;
|
if (isNaN(x as number) || isNaN(y as number) || isNaN(z as number)) return;
|
||||||
if (!disableAnimate && animates?.update) {
|
if (animate && !disableAnimate && animates?.update) {
|
||||||
const groupAnimates = animates.update.filter(
|
const groupAnimates = animates.update.filter(
|
||||||
({ shapeId, fields = [] }) =>
|
({ shapeId, fields = [] }) =>
|
||||||
(!shapeId || shapeId === 'group') &&
|
(!shapeId || shapeId === 'group') &&
|
||||||
(fields.includes('x') || fields.includes('y')),
|
(fields.includes('x') || fields.includes('y')),
|
||||||
);
|
);
|
||||||
if (groupAnimates.length) {
|
if (groupAnimates.length) {
|
||||||
animateShapes(
|
const animations = animateShapes(
|
||||||
{ update: groupAnimates },
|
{ update: groupAnimates },
|
||||||
{ group: { x, y, z } } as any, // targetStylesMap
|
{ group: { x, y, z } } as any, // targetStylesMap
|
||||||
this.shapeMap, // shapeMap
|
this.shapeMap, // shapeMap
|
||||||
@ -156,12 +168,14 @@ export default class Node extends Item {
|
|||||||
'update',
|
'update',
|
||||||
[],
|
[],
|
||||||
this.animateFrameListener,
|
this.animateFrameListener,
|
||||||
() => onfinish(displayModel.id),
|
(canceled) => onfinish(displayModel.id, canceled),
|
||||||
);
|
);
|
||||||
|
this.groupAnimations = animations;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group.setLocalPosition(x, y, z);
|
group.setLocalPosition(x, y, z);
|
||||||
|
onfinish(displayModel.id, !animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public clone(
|
public clone(
|
||||||
@ -294,6 +308,12 @@ export default class Node extends Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getPosition(): Point {
|
public getPosition(): Point {
|
||||||
|
const initiated =
|
||||||
|
this.shapeMap.keyShape && this.group.attributes.x !== undefined;
|
||||||
|
if (initiated) {
|
||||||
|
const { center } = this.shapeMap.keyShape.getRenderBounds();
|
||||||
|
return { x: center[0], y: center[1], z: center[2] };
|
||||||
|
}
|
||||||
const { x = 0, y = 0, z = 0 } = this.model.data;
|
const { x = 0, y = 0, z = 0 } = this.model.data;
|
||||||
return { x: x as number, y: y as number, z: z as number };
|
return { x: x as number, y: y as number, z: z as number };
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { Graph as GraphLib, GraphView, ID } from '@antv/graphlib';
|
import { Graph as GraphLib, GraphView, ID } from '@antv/graphlib';
|
||||||
import {
|
import { clone, isArray, isObject } from '@antv/util';
|
||||||
clone,
|
|
||||||
isArray,
|
|
||||||
isFunction,
|
|
||||||
isNumber,
|
|
||||||
isObject,
|
|
||||||
isString,
|
|
||||||
} from '@antv/util';
|
|
||||||
import { registery as registry } from '../../stdlib';
|
import { registery as registry } from '../../stdlib';
|
||||||
import { ComboModel, ComboUserModel, GraphData, IGraph } from '../../types';
|
import { ComboModel, ComboUserModel, GraphData, IGraph } from '../../types';
|
||||||
import { ComboUserModelData } from '../../types/combo';
|
import { ComboUserModelData } from '../../types/combo';
|
||||||
import { DataChangeType, GraphCore } from '../../types/data';
|
import {
|
||||||
|
DataChangeType,
|
||||||
|
DataConfig,
|
||||||
|
FetchDataConfig,
|
||||||
|
GraphCore,
|
||||||
|
InlineGraphDataConfig,
|
||||||
|
InlineTreeDataConfig,
|
||||||
|
} from '../../types/data';
|
||||||
import {
|
import {
|
||||||
EdgeModel,
|
EdgeModel,
|
||||||
EdgeModelData,
|
EdgeModelData,
|
||||||
@ -28,9 +28,10 @@ import { getExtension } from '../../util/extension';
|
|||||||
import {
|
import {
|
||||||
deconstructData,
|
deconstructData,
|
||||||
graphComboTreeDfs,
|
graphComboTreeDfs,
|
||||||
graphCoreTreeDfs,
|
graphData2TreeData,
|
||||||
isSucceed,
|
treeData2GraphData,
|
||||||
validateComboStrucutre,
|
validateComboStrucutre,
|
||||||
|
traverse,
|
||||||
} from '../../util/data';
|
} from '../../util/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,8 +50,6 @@ export class DataController {
|
|||||||
*/
|
*/
|
||||||
public graphCore: GraphCore;
|
public graphCore: GraphCore;
|
||||||
|
|
||||||
private comboTreeView: GraphView<any, any>;
|
|
||||||
|
|
||||||
constructor(graph: IGraph<any, any>) {
|
constructor(graph: IGraph<any, any>) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
this.tap();
|
this.tap();
|
||||||
@ -142,6 +141,9 @@ export class DataController {
|
|||||||
private tap() {
|
private tap() {
|
||||||
this.extensions = this.getExtensions();
|
this.extensions = this.getExtensions();
|
||||||
this.graph.hooks.datachange.tap(this.onDataChange.bind(this));
|
this.graph.hooks.datachange.tap(this.onDataChange.bind(this));
|
||||||
|
this.graph.hooks.treecollapseexpand.tap(
|
||||||
|
this.onTreeCollapseExpand.bind(this),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,24 +163,24 @@ export class DataController {
|
|||||||
* Listener of graph's datachange hook.
|
* Listener of graph's datachange hook.
|
||||||
* @param param contains new graph data and type of data change
|
* @param param contains new graph data and type of data change
|
||||||
*/
|
*/
|
||||||
private onDataChange(param: { data: GraphData; type: DataChangeType }) {
|
private onDataChange(param: { data: DataConfig; type: DataChangeType }) {
|
||||||
const { data, type: changeType } = param;
|
const { data, type: changeType } = param;
|
||||||
const change = () => {
|
const change = () => {
|
||||||
switch (changeType) {
|
switch (changeType) {
|
||||||
case 'remove':
|
case 'remove':
|
||||||
this.removeData(data);
|
this.removeData(data as GraphData);
|
||||||
break;
|
break;
|
||||||
case 'update':
|
case 'update':
|
||||||
this.updateData(data);
|
this.updateData(data as GraphData);
|
||||||
break;
|
break;
|
||||||
case 'moveCombo':
|
case 'moveCombo':
|
||||||
this.moveCombo(data);
|
this.moveCombo(data as GraphData);
|
||||||
break;
|
break;
|
||||||
case 'addCombo':
|
case 'addCombo':
|
||||||
this.addCombo(data);
|
this.addCombo(data as GraphData);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// 'replace' | 'mergeReplace' | 'union'
|
// changeType is 'replace' | 'mergeReplace' | 'union'
|
||||||
this.changeData(data, changeType);
|
this.changeData(data, changeType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -191,16 +193,30 @@ export class DataController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onTreeCollapseExpand(params: {
|
||||||
|
ids: ID[];
|
||||||
|
action: 'collapse' | 'expand';
|
||||||
|
}) {
|
||||||
|
const { ids, action } = params;
|
||||||
|
ids.forEach((id) => {
|
||||||
|
this.userGraphCore.mergeNodeData(id, {
|
||||||
|
collapsed: action === 'collapse',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change data by replace, merge repalce, or union.
|
* Change data by replace, merge repalce, or union.
|
||||||
* @param data new data
|
* @param data new data
|
||||||
* @param changeType type of data change, 'replace' means discard the old data. 'mergeReplace' means merge the common part. 'union' means merge whole sets of old and new one
|
* @param changeType type of data change, 'replace' means discard the old data. 'mergeReplace' means merge the common part. 'union' means merge whole sets of old and new one
|
||||||
*/
|
*/
|
||||||
private changeData(
|
private changeData(
|
||||||
data: GraphData,
|
dataConfig: DataConfig,
|
||||||
changeType: 'replace' | 'mergeReplace' | 'union',
|
changeType: 'replace' | 'mergeReplace' | 'union',
|
||||||
) {
|
) {
|
||||||
const { userGraphCore } = this;
|
const { type: dataType, data } = this.formatData(dataConfig) || {};
|
||||||
|
if (!dataType) return;
|
||||||
|
|
||||||
if (changeType === 'replace') {
|
if (changeType === 'replace') {
|
||||||
this.userGraphCore = new GraphLib<NodeUserModelData, EdgeUserModelData>({
|
this.userGraphCore = new GraphLib<NodeUserModelData, EdgeUserModelData>({
|
||||||
nodes: data.nodes.concat(
|
nodes: data.nodes.concat(
|
||||||
@ -224,10 +240,6 @@ export class DataController {
|
|||||||
edges,
|
edges,
|
||||||
});
|
});
|
||||||
if (combos?.length) {
|
if (combos?.length) {
|
||||||
this.comboTreeView = new GraphView<NodeModelData, EdgeModelData>({
|
|
||||||
graph: this.graphCore,
|
|
||||||
cache: 'manual',
|
|
||||||
});
|
|
||||||
this.graphCore.attachTreeStructure('combo');
|
this.graphCore.attachTreeStructure('combo');
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
if (node.data.parentId) {
|
if (node.data.parentId) {
|
||||||
@ -257,9 +269,10 @@ export class DataController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const { userGraphCore } = this;
|
||||||
const prevData = deconstructData({
|
const prevData = deconstructData({
|
||||||
nodes: userGraphCore.getAllNodes(),
|
nodes: userGraphCore.getAllNodes(),
|
||||||
edges: userGraphCore.getAllEdges(),
|
edges: [],
|
||||||
});
|
});
|
||||||
const { nodes = [], edges = [], combos = [] } = data;
|
const { nodes = [], edges = [], combos = [] } = data;
|
||||||
const nodesAndCombos = nodes.concat(
|
const nodesAndCombos = nodes.concat(
|
||||||
@ -294,6 +307,7 @@ export class DataController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========== edge ============
|
// =========== edge ============
|
||||||
|
prevData.edges = userGraphCore.getAllEdges();
|
||||||
if (!prevData.edges.length) {
|
if (!prevData.edges.length) {
|
||||||
userGraphCore.addEdges(edges);
|
userGraphCore.addEdges(edges);
|
||||||
} else {
|
} else {
|
||||||
@ -317,6 +331,15 @@ export class DataController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.edges?.length) {
|
||||||
|
const { userGraphCore } = this;
|
||||||
|
// convert and store tree structure to graphCore
|
||||||
|
this.updateTreeGraph(dataType, {
|
||||||
|
nodes: userGraphCore.getAllNodes(),
|
||||||
|
edges: userGraphCore.getAllEdges(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -331,12 +354,14 @@ export class DataController {
|
|||||||
const prevEdges = userGraphCore.getAllEdges();
|
const prevEdges = userGraphCore.getAllEdges();
|
||||||
if (prevNodesAndCombos.length && nodesAndCombos.length) {
|
if (prevNodesAndCombos.length && nodesAndCombos.length) {
|
||||||
// update the parentId
|
// update the parentId
|
||||||
nodesAndCombos.forEach((item) => {
|
if (this.graphCore.hasTreeStructure('combo')) {
|
||||||
const { parentId } = item.data;
|
nodesAndCombos.forEach((item) => {
|
||||||
this.graphCore.getChildren(item.id, 'combo').forEach((child) => {
|
const { parentId } = item.data;
|
||||||
userGraphCore.mergeNodeData(child.id, { parentId });
|
this.graphCore.getChildren(item.id, 'combo').forEach((child) => {
|
||||||
|
userGraphCore.mergeNodeData(child.id, { parentId });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
// remove the node
|
// remove the node
|
||||||
userGraphCore.removeNodes(nodesAndCombos.map((node) => node.id));
|
userGraphCore.removeNodes(nodesAndCombos.map((node) => node.id));
|
||||||
}
|
}
|
||||||
@ -353,9 +378,11 @@ export class DataController {
|
|||||||
* Update part of old data.
|
* Update part of old data.
|
||||||
* @param data data to be updated which is part of old one
|
* @param data data to be updated which is part of old one
|
||||||
*/
|
*/
|
||||||
private updateData(data: GraphData) {
|
private updateData(dataConfig: DataConfig) {
|
||||||
const { userGraphCore } = this;
|
const { userGraphCore } = this;
|
||||||
const { nodes = [], edges = [], combos = [] } = data;
|
const { type: dataType, data } = this.formatData(dataConfig);
|
||||||
|
if (!dataType) return;
|
||||||
|
const { nodes = [], edges = [], combos = [] } = data as GraphData;
|
||||||
const {
|
const {
|
||||||
nodes: prevNodes,
|
nodes: prevNodes,
|
||||||
edges: prevEdges,
|
edges: prevEdges,
|
||||||
@ -453,6 +480,38 @@ export class DataController {
|
|||||||
userGraphCore.mergeNodeData(id, data);
|
userGraphCore.mergeNodeData(id, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (edges.length) {
|
||||||
|
// convert and store tree structure to graphCore
|
||||||
|
this.updateTreeGraph(dataType, {
|
||||||
|
nodes: this.userGraphCore.getAllNodes(),
|
||||||
|
edges: this.userGraphCore.getAllEdges(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatData(dataConfig: DataConfig): {
|
||||||
|
data: GraphData;
|
||||||
|
type: 'graphData' | 'treeData' | 'fetch';
|
||||||
|
} {
|
||||||
|
const { type, value } = dataConfig as
|
||||||
|
| InlineGraphDataConfig
|
||||||
|
| InlineTreeDataConfig
|
||||||
|
| FetchDataConfig;
|
||||||
|
let data = value;
|
||||||
|
if (!type) {
|
||||||
|
data = dataConfig as GraphData;
|
||||||
|
} else if (type === 'treeData') {
|
||||||
|
data = treeData2GraphData(value);
|
||||||
|
} else if (type === 'fetch') {
|
||||||
|
// TODO: fetch
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
'Input data type is invalid, the type shuold be "graphData", "treeData", or "fetch".',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return { type: type || 'graphData', data: data as GraphData };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -592,9 +651,22 @@ export class DataController {
|
|||||||
const changeMap: {
|
const changeMap: {
|
||||||
[id: string]: boolean;
|
[id: string]: boolean;
|
||||||
} = {};
|
} = {};
|
||||||
|
const treeChanges = [];
|
||||||
event.changes.forEach((change) => {
|
event.changes.forEach((change) => {
|
||||||
const { value, id } = change;
|
const id = change.id || change.value?.id;
|
||||||
changeMap[id || value.id] = true;
|
if (id !== undefined) {
|
||||||
|
changeMap[id] = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
'TreeStructureAttached',
|
||||||
|
'TreeStructureChanged',
|
||||||
|
'TreeStructureChanged',
|
||||||
|
].includes(change.type)
|
||||||
|
) {
|
||||||
|
treeChanges.push(change);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
nodes.forEach((model) => {
|
nodes.forEach((model) => {
|
||||||
newModelMap[model.id] = { type: 'node', model };
|
newModelMap[model.id] = { type: 'node', model };
|
||||||
@ -633,6 +705,7 @@ export class DataController {
|
|||||||
const { model: newModel } = newModelMap[id] || {};
|
const { model: newModel } = newModelMap[id] || {};
|
||||||
// remove
|
// remove
|
||||||
if (!newModel) {
|
if (!newModel) {
|
||||||
|
// remove a combo, put the children to upper parent
|
||||||
if (prevModel.data._isCombo) {
|
if (prevModel.data._isCombo) {
|
||||||
graphCore.getChildren(id, 'combo').forEach((child) => {
|
graphCore.getChildren(id, 'combo').forEach((child) => {
|
||||||
parentMap[child.id] = {
|
parentMap[child.id] = {
|
||||||
@ -641,9 +714,43 @@ export class DataController {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// if it has combo parent, remove it from the parent's children list
|
||||||
if (prevModel.data.parentId) {
|
if (prevModel.data.parentId) {
|
||||||
graphCore.setParent(id, undefined, 'combo');
|
graphCore.setParent(id, undefined, 'combo');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for tree graph view, show the succeed nodes and edges
|
||||||
|
const succeedIds = [];
|
||||||
|
graphCore.dfsTree(
|
||||||
|
id,
|
||||||
|
(child) => {
|
||||||
|
succeedIds.push(child.id);
|
||||||
|
},
|
||||||
|
'tree',
|
||||||
|
);
|
||||||
|
const succeedEdgeIds = graphCore
|
||||||
|
.getAllEdges()
|
||||||
|
.filter(
|
||||||
|
({ source, target }) =>
|
||||||
|
succeedIds.includes(source) && succeedIds.includes(target),
|
||||||
|
)
|
||||||
|
.map((edge) => edge.id);
|
||||||
|
this.graph.showItem(
|
||||||
|
succeedIds
|
||||||
|
.filter((succeedId) => succeedId !== id)
|
||||||
|
.concat(succeedEdgeIds),
|
||||||
|
);
|
||||||
|
|
||||||
|
// for tree graph view, remove the node from the parent's children list
|
||||||
|
graphCore.setParent(id, undefined, 'tree');
|
||||||
|
// for tree graph view, make the its children to be roots
|
||||||
|
graphCore
|
||||||
|
.getChildren(id, 'tree')
|
||||||
|
.forEach((child) =>
|
||||||
|
graphCore.setParent(child.id, undefined, 'tree'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove the node data
|
||||||
graphCore.removeNode(id);
|
graphCore.removeNode(id);
|
||||||
delete parentMap[prevModel.id];
|
delete parentMap[prevModel.id];
|
||||||
}
|
}
|
||||||
@ -682,6 +789,21 @@ export class DataController {
|
|||||||
graphCore.mergeNodeData(id, { parentId: parentMap[id].new });
|
graphCore.mergeNodeData(id, { parentId: parentMap[id].new });
|
||||||
graphCore.setParent(id, parentMap[id].new, 'combo');
|
graphCore.setParent(id, parentMap[id].new, 'combo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// update tree structure
|
||||||
|
treeChanges.forEach((change) => {
|
||||||
|
const { type, treeKey, nodeId, newParentId } = change;
|
||||||
|
if (type === 'TreeStructureAttached') {
|
||||||
|
graphCore.attachTreeStructure(treeKey);
|
||||||
|
return;
|
||||||
|
} else if (type === 'TreeStructureChanged') {
|
||||||
|
graphCore.setParent(nodeId, newParentId, treeKey);
|
||||||
|
return;
|
||||||
|
} else if (type === 'TreeStructureDetached') {
|
||||||
|
graphCore.detachTreeStructure(treeKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// situation 2: idMaps is complete
|
// situation 2: idMaps is complete
|
||||||
// calculate the final idMap which maps the ids from final transformed data to their comes from ids in userData
|
// calculate the final idMap which maps the ids from final transformed data to their comes from ids in userData
|
||||||
@ -704,15 +826,17 @@ export class DataController {
|
|||||||
const { changes } = event;
|
const { changes } = event;
|
||||||
changes.forEach((change) => {
|
changes.forEach((change) => {
|
||||||
const { value, id, type } = change;
|
const { value, id, type } = change;
|
||||||
// TODO: temporary skip. how to handle tree change events?
|
if (type === 'TreeStructureAttached') {
|
||||||
if (
|
graphCore.attachTreeStructure(change.treeKey);
|
||||||
[
|
|
||||||
'TreeStructureAttached',
|
|
||||||
'TreeStructureDetached',
|
|
||||||
'TreeStructureChanged',
|
|
||||||
].includes(type)
|
|
||||||
)
|
|
||||||
return;
|
return;
|
||||||
|
} else if (type === 'TreeStructureChanged') {
|
||||||
|
const { newParentId, nodeId, treeKey } = change;
|
||||||
|
graphCore.setParent(nodeId, newParentId, treeKey);
|
||||||
|
return;
|
||||||
|
} else if (type === 'TreeStructureDetached') {
|
||||||
|
graphCore.detachTreeStructure(change.treeKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const dataId = id || value.id;
|
const dataId = id || value.id;
|
||||||
changeMap[dataId] = changeMap[dataId] || [];
|
changeMap[dataId] = changeMap[dataId] || [];
|
||||||
changeMap[dataId].push(type.toLawerCase());
|
changeMap[dataId].push(type.toLawerCase());
|
||||||
@ -727,15 +851,14 @@ export class DataController {
|
|||||||
const oldValue = prevModelMap[newId];
|
const oldValue = prevModelMap[newId];
|
||||||
const isNodeOrCombo = graphCore.hasNode(newId);
|
const isNodeOrCombo = graphCore.hasNode(newId);
|
||||||
if (newValue && !oldValue) {
|
if (newValue && !oldValue) {
|
||||||
const addFunc = isNodeOrCombo
|
isNodeOrCombo
|
||||||
? graphCore.addNode
|
? graphCore.addNode(newValue)
|
||||||
: graphCore.addEdge;
|
: graphCore.addEdge(newValue);
|
||||||
addFunc(newValue);
|
|
||||||
} else if (!newValue && oldValue) {
|
} else if (!newValue && oldValue) {
|
||||||
const removeFunc = isNodeOrCombo
|
isNodeOrCombo
|
||||||
? graphCore.removeNode
|
? graphCore.removeNode(newId)
|
||||||
: graphCore.removeEdge;
|
: graphCore.removeEdge(newId);
|
||||||
removeFunc(newId);
|
// TODO: update combo tree and tree graph
|
||||||
} else {
|
} else {
|
||||||
if (!comesFromIds?.length) {
|
if (!comesFromIds?.length) {
|
||||||
// no comesForm, find same id in userGraphCore to follow the change, if it not found, diff new and old data value of graphCore (inner data)
|
// no comesForm, find same id in userGraphCore to follow the change, if it not found, diff new and old data value of graphCore (inner data)
|
||||||
@ -748,11 +871,9 @@ export class DataController {
|
|||||||
isNodeOrCombo,
|
isNodeOrCombo,
|
||||||
diff,
|
diff,
|
||||||
);
|
);
|
||||||
} else {
|
} else if (changeMap[comesFromIds[0]]?.length) {
|
||||||
// follow the corresponding data event in userGraphCore
|
// follow the corresponding data event in userGraphCore
|
||||||
const comesFromChanges = changeMap[comesFromIds[0]];
|
syncUpdateToGraphCore(newId, newValue, oldValue, isNodeOrCombo);
|
||||||
if (comesFromChanges?.length)
|
|
||||||
syncUpdateToGraphCore(newId, newValue, oldValue, isNodeOrCombo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -771,7 +892,6 @@ export class DataController {
|
|||||||
graphCore.setParent(node.id, node.data.parentId as ID, 'combo');
|
graphCore.setParent(node.id, node.data.parentId as ID, 'combo');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.comboTreeView?.refreshCache();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -798,6 +918,34 @@ export class DataController {
|
|||||||
});
|
});
|
||||||
return { data: dataCloned, idMaps };
|
return { data: dataCloned, idMaps };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert and store tree structure to graphCore
|
||||||
|
* @param dataType
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
private updateTreeGraph(dataType, data) {
|
||||||
|
this.userGraphCore.attachTreeStructure('tree');
|
||||||
|
if (dataType === 'treeData') {
|
||||||
|
// tree structure storing
|
||||||
|
data.edges.forEach((edge) => {
|
||||||
|
const { source, target } = edge;
|
||||||
|
this.userGraphCore.setParent(target, source, 'tree');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// graph data to tree structure and storing
|
||||||
|
const rootIds = data.nodes
|
||||||
|
.filter((node) => node.data.isRoot)
|
||||||
|
.map((node) => node.id);
|
||||||
|
graphData2TreeData({}, data, rootIds).forEach((tree) => {
|
||||||
|
traverse(tree, (node) => {
|
||||||
|
node.children?.forEach((child) => {
|
||||||
|
this.userGraphCore.setParent(child.id, node.id, 'tree');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,8 +126,6 @@ export class ItemController {
|
|||||||
[id: string]: Node | Edge | Combo | Group;
|
[id: string]: Node | Edge | Combo | Group;
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
// private comboTreeView: GraphView<any, any>;
|
|
||||||
|
|
||||||
constructor(graph: IGraph<any, any>) {
|
constructor(graph: IGraph<any, any>) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
// get mapper for node / edge / combo
|
// get mapper for node / edge / combo
|
||||||
@ -168,6 +166,9 @@ export class ItemController {
|
|||||||
this.graph.hooks.transientupdate.tap(this.onTransientUpdate.bind(this));
|
this.graph.hooks.transientupdate.tap(this.onTransientUpdate.bind(this));
|
||||||
this.graph.hooks.viewportchange.tap(this.onViewportChange.bind(this));
|
this.graph.hooks.viewportchange.tap(this.onViewportChange.bind(this));
|
||||||
this.graph.hooks.themechange.tap(this.onThemeChange.bind(this));
|
this.graph.hooks.themechange.tap(this.onThemeChange.bind(this));
|
||||||
|
this.graph.hooks.treecollapseexpand.tap(
|
||||||
|
this.onTreeCollapseExpand.bind(this),
|
||||||
|
);
|
||||||
this.graph.hooks.destroy.tap(this.onDestroy.bind(this));
|
this.graph.hooks.destroy.tap(this.onDestroy.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +259,7 @@ export class ItemController {
|
|||||||
this.renderCombos(combos, theme.combo, graphCore);
|
this.renderCombos(combos, theme.combo, graphCore);
|
||||||
this.renderEdges(edges, theme.edge);
|
this.renderEdges(edges, theme.edge);
|
||||||
this.sortByComboTree(graphCore);
|
this.sortByComboTree(graphCore);
|
||||||
|
// collapse the combos which has 'collapsed' in initial data
|
||||||
if (graphCore.hasTreeStructure('combo')) {
|
if (graphCore.hasTreeStructure('combo')) {
|
||||||
graphCoreTreeDfs(
|
graphCoreTreeDfs(
|
||||||
graphCore,
|
graphCore,
|
||||||
@ -266,8 +268,21 @@ export class ItemController {
|
|||||||
if (child.data.collapsed) this.collapseCombo(graphCore, child);
|
if (child.data.collapsed) this.collapseCombo(graphCore, child);
|
||||||
},
|
},
|
||||||
'BT',
|
'BT',
|
||||||
|
'combo',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// collapse the sub tree which has 'collapsed' in initial data
|
||||||
|
const collapseNodes = [];
|
||||||
|
graphCoreTreeDfs(
|
||||||
|
graphCore,
|
||||||
|
graphCore.getRoots('tree'),
|
||||||
|
(child) => {
|
||||||
|
if (child.data.collapsed) collapseNodes.push(child);
|
||||||
|
},
|
||||||
|
'BT',
|
||||||
|
'tree',
|
||||||
|
);
|
||||||
|
this.collapseSubTree(collapseNodes, graphCore, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -280,14 +295,21 @@ export class ItemController {
|
|||||||
graphCore: GraphCore;
|
graphCore: GraphCore;
|
||||||
theme: ThemeSpecification;
|
theme: ThemeSpecification;
|
||||||
upsertAncestors?: boolean;
|
upsertAncestors?: boolean;
|
||||||
|
animate?: boolean;
|
||||||
action?: 'updatePosition';
|
action?: 'updatePosition';
|
||||||
|
callback?: (
|
||||||
|
model: NodeModel | EdgeModel | ComboModel,
|
||||||
|
canceled?: boolean,
|
||||||
|
) => void;
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
changes,
|
changes,
|
||||||
graphCore,
|
graphCore,
|
||||||
action,
|
action,
|
||||||
|
animate = true,
|
||||||
upsertAncestors = true,
|
upsertAncestors = true,
|
||||||
theme = {},
|
theme = {},
|
||||||
|
callback = () => {},
|
||||||
} = param;
|
} = param;
|
||||||
const groupedChanges = getGroupedChanges(graphCore, changes);
|
const groupedChanges = getGroupedChanges(graphCore, changes);
|
||||||
const { itemMap } = this;
|
const { itemMap } = this;
|
||||||
@ -298,10 +320,9 @@ export class ItemController {
|
|||||||
({ value }) => {
|
({ value }) => {
|
||||||
const { id } = value;
|
const { id } = value;
|
||||||
const item = itemMap[id];
|
const item = itemMap[id];
|
||||||
if (item) {
|
if (!item) return;
|
||||||
item.destroy();
|
item.destroy();
|
||||||
delete itemMap[id];
|
delete itemMap[id];
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -381,8 +402,16 @@ export class ItemController {
|
|||||||
const onlyMove = action === 'updatePosition';
|
const onlyMove = action === 'updatePosition';
|
||||||
const item = itemMap[id] as Node | Combo;
|
const item = itemMap[id] as Node | Combo;
|
||||||
const type = item.getType();
|
const type = item.getType();
|
||||||
if (onlyMove && type === 'node' && isNaN(current.x) && isNaN(current.y))
|
const innerModel = graphCore.getNode(id);
|
||||||
|
if (
|
||||||
|
onlyMove &&
|
||||||
|
type === 'node' &&
|
||||||
|
isNaN(current.x) &&
|
||||||
|
isNaN(current.y)
|
||||||
|
) {
|
||||||
|
callback(innerModel, true);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// update the theme if the dataType value is changed
|
// update the theme if the dataType value is changed
|
||||||
let itemTheme;
|
let itemTheme;
|
||||||
if (
|
if (
|
||||||
@ -396,7 +425,6 @@ export class ItemController {
|
|||||||
nodeTheme,
|
nodeTheme,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const innerModel = graphCore.getNode(id);
|
|
||||||
const relatedEdgeInnerModels = graphCore.getRelatedEdges(id);
|
const relatedEdgeInnerModels = graphCore.getRelatedEdges(id);
|
||||||
const nodeRelatedIdsToUpdate: ID[] = [];
|
const nodeRelatedIdsToUpdate: ID[] = [];
|
||||||
relatedEdgeInnerModels.forEach((edge) => {
|
relatedEdgeInnerModels.forEach((edge) => {
|
||||||
@ -415,11 +443,13 @@ export class ItemController {
|
|||||||
isReplace,
|
isReplace,
|
||||||
itemTheme,
|
itemTheme,
|
||||||
onlyMove,
|
onlyMove,
|
||||||
|
animate,
|
||||||
// call after updating finished
|
// call after updating finished
|
||||||
() => {
|
(_, canceled) => {
|
||||||
item.onframe();
|
item.onframe?.();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
item.onframe = undefined;
|
item.onframe = undefined;
|
||||||
|
callback(innerModel, canceled);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -476,7 +506,7 @@ export class ItemController {
|
|||||||
this.graph.hideItem(innerModel.id);
|
this.graph.hideItem(innerModel.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
updateRelates();
|
updateRelatesThrottle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 6. update edges' data ===
|
// === 6. update edges' data ===
|
||||||
@ -513,7 +543,15 @@ export class ItemController {
|
|||||||
}
|
}
|
||||||
const item = itemMap[id];
|
const item = itemMap[id];
|
||||||
const innerModel = graphCore.getEdge(id);
|
const innerModel = graphCore.getEdge(id);
|
||||||
item.update(innerModel, { current, previous }, isReplace, itemTheme);
|
item.update(
|
||||||
|
innerModel,
|
||||||
|
{ current, previous },
|
||||||
|
isReplace,
|
||||||
|
itemTheme,
|
||||||
|
undefined,
|
||||||
|
animate,
|
||||||
|
(_, canceled) => callback(innerModel, canceled),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,9 +576,25 @@ export class ItemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === 8. combo tree structure change, resort the shapes ===
|
// === 8. combo tree structure change, resort the shapes ===
|
||||||
if (groupedChanges.TreeStructureChanged.length) {
|
if (groupedChanges.ComboStructureChanged.length) {
|
||||||
this.sortByComboTree(graphCore);
|
this.sortByComboTree(graphCore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === 9. tree data structure change, hide the new node and edge while one of the ancestor is collapsed ===
|
||||||
|
if (groupedChanges.TreeStructureChanged.length) {
|
||||||
|
groupedChanges.TreeStructureChanged.forEach((change) => {
|
||||||
|
const { nodeId } = change;
|
||||||
|
// hide it when an ancestor is collapsed
|
||||||
|
let parent = graphCore.getParent(nodeId, 'tree');
|
||||||
|
while (parent) {
|
||||||
|
if (parent.data.collapsed) {
|
||||||
|
this.graph.hideItem(nodeId, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = graphCore.getParent(parent.id, 'tree');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -593,21 +647,20 @@ export class ItemController {
|
|||||||
if (type === 'edge') {
|
if (type === 'edge') {
|
||||||
item.show(animate);
|
item.show(animate);
|
||||||
} else {
|
} else {
|
||||||
let anccestorCollapsed = false;
|
|
||||||
if (graphCore.hasTreeStructure('combo')) {
|
if (graphCore.hasTreeStructure('combo')) {
|
||||||
|
let anccestorCollapsed = false;
|
||||||
traverseAncestors(graphCore, [item.model], (model) => {
|
traverseAncestors(graphCore, [item.model], (model) => {
|
||||||
if (model.data.collapsed) anccestorCollapsed = true;
|
if (model.data.collapsed) anccestorCollapsed = true;
|
||||||
return anccestorCollapsed;
|
return anccestorCollapsed;
|
||||||
});
|
});
|
||||||
if (anccestorCollapsed) return;
|
if (anccestorCollapsed) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const relatedEdges = graphCore.getRelatedEdges(id);
|
const relatedEdges = graphCore.getRelatedEdges(id);
|
||||||
|
|
||||||
item.show(animate);
|
item.show(animate);
|
||||||
relatedEdges.forEach(({ id: edgeId, source, target }) => {
|
relatedEdges.forEach(({ id: edgeId, source, target }) => {
|
||||||
if (this.getItemVisible(source) && this.getItemVisible(target))
|
if (this.getItemVisible(source) && this.getItemVisible(target))
|
||||||
this.itemMap[edgeId]?.show();
|
this.itemMap[edgeId]?.show(animate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -615,7 +668,7 @@ export class ItemController {
|
|||||||
if (type !== 'edge') {
|
if (type !== 'edge') {
|
||||||
const relatedEdges = graphCore.getRelatedEdges(id);
|
const relatedEdges = graphCore.getRelatedEdges(id);
|
||||||
relatedEdges.forEach(({ id: edgeId }) => {
|
relatedEdges.forEach(({ id: edgeId }) => {
|
||||||
this.itemMap[edgeId]?.hide();
|
this.itemMap[edgeId]?.hide(animate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -979,11 +1032,13 @@ export class ItemController {
|
|||||||
console.warn(
|
console.warn(
|
||||||
`The source node ${source} is not exist in the graph for edge ${id}, please add the node first`,
|
`The source node ${source} is not exist in the graph for edge ${id}, please add the node first`,
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!targetItem) {
|
if (!targetItem) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`The source node ${source} is not exist in the graph for edge ${id}, please add the node first`,
|
`The source node ${source} is not exist in the graph for edge ${id}, please add the node first`,
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// get the base styles from theme
|
// get the base styles from theme
|
||||||
let dataType;
|
let dataType;
|
||||||
@ -1164,6 +1219,134 @@ export class ItemController {
|
|||||||
// remove related virtual edges
|
// remove related virtual edges
|
||||||
this.graph.removeData('edge', uniq(relatedVirtualEdgeIds));
|
this.graph.removeData('edge', uniq(relatedVirtualEdgeIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapse or expand a sub tree according to action
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
private onTreeCollapseExpand(params: {
|
||||||
|
ids: ID[];
|
||||||
|
animate: boolean;
|
||||||
|
action: 'collapse' | 'expand';
|
||||||
|
graphCore: GraphCore;
|
||||||
|
}) {
|
||||||
|
const { ids, animate, action, graphCore } = params;
|
||||||
|
const rootModels = ids.map((id) => graphCore.getNode(id));
|
||||||
|
switch (action) {
|
||||||
|
case 'collapse':
|
||||||
|
this.collapseSubTree(rootModels, graphCore, animate);
|
||||||
|
break;
|
||||||
|
case 'expand':
|
||||||
|
default:
|
||||||
|
this.expandSubTree(rootModels, graphCore, animate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapse sub tree(s).
|
||||||
|
* @param rootModels The root node models of sub trees
|
||||||
|
* @param graphCore
|
||||||
|
* @param animate Whether enable animations for expanding, true by default
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private collapseSubTree(
|
||||||
|
rootModels: NodeModel[],
|
||||||
|
graphCore: GraphCore,
|
||||||
|
animate: boolean = true,
|
||||||
|
) {
|
||||||
|
let positions = [];
|
||||||
|
rootModels.forEach((root) => {
|
||||||
|
let shouldCollapse = true;
|
||||||
|
const nodes = [];
|
||||||
|
graphCoreTreeDfs(
|
||||||
|
graphCore,
|
||||||
|
[root],
|
||||||
|
(node) => {
|
||||||
|
if (node.id === root.id) return;
|
||||||
|
const neighbors = graphCore.getNeighbors(node.id);
|
||||||
|
if (
|
||||||
|
neighbors.length > 2 ||
|
||||||
|
(!graphCore.getChildren(node.id, 'tree')?.length &&
|
||||||
|
neighbors.length > 1)
|
||||||
|
) {
|
||||||
|
shouldCollapse = false;
|
||||||
|
}
|
||||||
|
nodes.push(node);
|
||||||
|
},
|
||||||
|
'TB',
|
||||||
|
'tree',
|
||||||
|
{
|
||||||
|
stopAllFn: () => !shouldCollapse,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (shouldCollapse) {
|
||||||
|
positions = positions.concat(
|
||||||
|
nodes.map((node) => ({
|
||||||
|
id: node.id,
|
||||||
|
data: { x: root.data.x, y: root.data.y },
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!positions.length) return;
|
||||||
|
this.graph.updateNodePosition(
|
||||||
|
positions,
|
||||||
|
undefined,
|
||||||
|
!animate,
|
||||||
|
(model, canceled) => {
|
||||||
|
this.graph.hideItem(model.id, canceled);
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand sub tree(s).
|
||||||
|
* @param rootModels The root node models of sub trees.
|
||||||
|
* @param graphCore
|
||||||
|
* @param animate Whether enable animations for expanding, true by default.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private expandSubTree(
|
||||||
|
rootModels: NodeModel[],
|
||||||
|
graphCore: GraphCore,
|
||||||
|
animate: boolean = true,
|
||||||
|
) {
|
||||||
|
let allNodeIds = [];
|
||||||
|
let allEdgeIds = [];
|
||||||
|
rootModels.forEach((root) => {
|
||||||
|
const nodeIds = [];
|
||||||
|
graphCoreTreeDfs(
|
||||||
|
graphCore,
|
||||||
|
[root],
|
||||||
|
(node) => nodeIds.push(node.id),
|
||||||
|
'TB',
|
||||||
|
'tree',
|
||||||
|
{
|
||||||
|
stopBranchFn: (node) => {
|
||||||
|
const shouldStop =
|
||||||
|
node.id !== root.id && (node.data.collapsed as boolean);
|
||||||
|
if (shouldStop) nodeIds.push(node.id);
|
||||||
|
return shouldStop;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
allEdgeIds = allEdgeIds.concat(
|
||||||
|
graphCore
|
||||||
|
.getAllEdges()
|
||||||
|
.filter(
|
||||||
|
(edge) =>
|
||||||
|
nodeIds.includes(edge.source) && nodeIds.includes(edge.target),
|
||||||
|
)
|
||||||
|
.map((edge) => edge.id),
|
||||||
|
);
|
||||||
|
allNodeIds = allNodeIds.concat(nodeIds.filter((id) => id !== root.id));
|
||||||
|
});
|
||||||
|
const ids = uniq(allNodeIds.concat(allEdgeIds));
|
||||||
|
this.graph.showItem(ids, !animate);
|
||||||
|
this.graph.layout(undefined, !animate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItemTheme = (
|
const getItemTheme = (
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Animation, DisplayObject, IAnimationEffectTiming } from '@antv/g';
|
import { Animation, DisplayObject, IAnimationEffectTiming } from '@antv/g';
|
||||||
|
import Hierarchy from '@antv/hierarchy';
|
||||||
import { Graph as GraphLib } from '@antv/graphlib';
|
import { Graph as GraphLib } from '@antv/graphlib';
|
||||||
import {
|
import {
|
||||||
isLayoutWithIterations,
|
isLayoutWithIterations,
|
||||||
@ -17,6 +18,7 @@ import {
|
|||||||
} from '../../types';
|
} from '../../types';
|
||||||
import { GraphCore } from '../../types/data';
|
import { GraphCore } from '../../types/data';
|
||||||
import { EdgeModelData } from '../../types/edge';
|
import { EdgeModelData } from '../../types/edge';
|
||||||
|
import { layoutOneTree } from '../../util/layout';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages layout extensions and graph layout.
|
* Manages layout extensions and graph layout.
|
||||||
@ -48,6 +50,7 @@ export class LayoutController {
|
|||||||
private async onLayout(params: {
|
private async onLayout(params: {
|
||||||
graphCore: GraphCore;
|
graphCore: GraphCore;
|
||||||
options: LayoutOptions;
|
options: LayoutOptions;
|
||||||
|
animate?: boolean;
|
||||||
}) {
|
}) {
|
||||||
/**
|
/**
|
||||||
* The final calculated result.
|
* The final calculated result.
|
||||||
@ -57,13 +60,15 @@ export class LayoutController {
|
|||||||
// Stop currentLayout if any.
|
// Stop currentLayout if any.
|
||||||
this.stopLayout();
|
this.stopLayout();
|
||||||
|
|
||||||
const { graphCore, options } = params;
|
const { graphCore, options, animate = true } = params;
|
||||||
const layoutNodes = graphCore
|
const layoutNodes = graphCore
|
||||||
.getAllNodes()
|
.getAllNodes()
|
||||||
.filter((node) => node.data.visible !== false && !node.data._isCombo);
|
.filter(
|
||||||
|
(node) => this.graph.getItemVisible(node.id) && !node.data._isCombo,
|
||||||
|
);
|
||||||
const layoutNodesIdMap = {};
|
const layoutNodesIdMap = {};
|
||||||
layoutNodes.forEach((node) => (layoutNodesIdMap[node.id] = true));
|
layoutNodes.forEach((node) => (layoutNodesIdMap[node.id] = true));
|
||||||
const layoutGraphCore = new GraphLib<NodeModelData, EdgeModelData>({
|
const layoutData = {
|
||||||
nodes: layoutNodes,
|
nodes: layoutNodes,
|
||||||
edges: graphCore
|
edges: graphCore
|
||||||
.getAllEdges()
|
.getAllEdges()
|
||||||
@ -71,7 +76,10 @@ export class LayoutController {
|
|||||||
(edge) =>
|
(edge) =>
|
||||||
layoutNodesIdMap[edge.source] && layoutNodesIdMap[edge.target],
|
layoutNodesIdMap[edge.source] && layoutNodesIdMap[edge.target],
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
|
const layoutGraphCore = new GraphLib<NodeModelData, EdgeModelData>(
|
||||||
|
layoutData,
|
||||||
|
);
|
||||||
|
|
||||||
this.graph.emit('startlayout');
|
this.graph.emit('startlayout');
|
||||||
|
|
||||||
@ -112,6 +120,19 @@ export class LayoutController {
|
|||||||
throw new Error(`Unknown layout algorithm: ${type}`);
|
throw new Error(`Unknown layout algorithm: ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Hierarchy[type]) {
|
||||||
|
// tree layout type
|
||||||
|
await this.handleTreeLayout(
|
||||||
|
type,
|
||||||
|
options,
|
||||||
|
animationEffectTiming,
|
||||||
|
graphCore,
|
||||||
|
layoutData,
|
||||||
|
animate,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize layout.
|
// Initialize layout.
|
||||||
const layout = new layoutCtor(rest);
|
const layout = new layoutCtor(rest);
|
||||||
this.currentLayout = layout;
|
this.currentLayout = layout;
|
||||||
@ -170,7 +191,57 @@ export class LayoutController {
|
|||||||
this.graph.emit('endlayout');
|
this.graph.emit('endlayout');
|
||||||
|
|
||||||
// Update nodes' positions.
|
// Update nodes' positions.
|
||||||
this.updateNodesPosition(positions);
|
this.updateNodesPosition(positions, animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleTreeLayout(
|
||||||
|
type,
|
||||||
|
options,
|
||||||
|
animationEffectTiming,
|
||||||
|
graphCore,
|
||||||
|
layoutData,
|
||||||
|
animate,
|
||||||
|
) {
|
||||||
|
const { animated = false, rootIds = [], begin = [0, 0] } = options;
|
||||||
|
const nodePositions = [];
|
||||||
|
const nodeMap = {};
|
||||||
|
// tree layout with tree data
|
||||||
|
const trees = graphCore
|
||||||
|
.getRoots('tree')
|
||||||
|
.filter(
|
||||||
|
(node) => !node.data._isCombo, // this.graph.getItemVisible(node.id) &&
|
||||||
|
)
|
||||||
|
.map((node) => ({ id: node.id, children: [] }));
|
||||||
|
|
||||||
|
trees.forEach((tree) => {
|
||||||
|
nodeMap[tree.id] = tree;
|
||||||
|
graphCore.dfsTree(
|
||||||
|
tree.id,
|
||||||
|
(node) => {
|
||||||
|
nodeMap[node.id].children = graphCore
|
||||||
|
.getChildren(node.id, 'tree')
|
||||||
|
.filter((node) => !node.data._isCombo)
|
||||||
|
.map((child) => {
|
||||||
|
nodeMap[child.id] = { id: child.id, children: [] };
|
||||||
|
return nodeMap[child.id];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'tree',
|
||||||
|
);
|
||||||
|
layoutOneTree(tree, type, options, nodeMap, nodePositions, begin);
|
||||||
|
});
|
||||||
|
if (animated) {
|
||||||
|
await this.animateLayoutWithoutIterations(
|
||||||
|
{ nodes: nodePositions, edges: [] },
|
||||||
|
animationEffectTiming,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.graph.emit('endlayout');
|
||||||
|
this.updateNodesPosition(
|
||||||
|
{ nodes: nodePositions, edges: [] },
|
||||||
|
animated || animate,
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopLayout() {
|
stopLayout() {
|
||||||
@ -202,8 +273,11 @@ export class LayoutController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateNodesPosition(positions: LayoutMapping) {
|
private updateNodesPosition(
|
||||||
this.graph.updateNodePosition(positions.nodes);
|
positions: LayoutMapping,
|
||||||
|
animate: boolean = true,
|
||||||
|
) {
|
||||||
|
this.graph.updateNodePosition(positions.nodes, undefined, !animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,7 @@ import { CameraAnimationOptions } from '../types/animate';
|
|||||||
import { BehaviorOptionsOf, BehaviorRegistry } from '../types/behavior';
|
import { BehaviorOptionsOf, BehaviorRegistry } from '../types/behavior';
|
||||||
import { ComboModel } from '../types/combo';
|
import { ComboModel } from '../types/combo';
|
||||||
import { Padding, Point } from '../types/common';
|
import { Padding, Point } from '../types/common';
|
||||||
import { DataChangeType, GraphCore } from '../types/data';
|
import { DataChangeType, DataConfig, GraphCore } from '../types/data';
|
||||||
import { EdgeModel, EdgeModelData } from '../types/edge';
|
import { EdgeModel, EdgeModelData } from '../types/edge';
|
||||||
import { Hooks, ViewportChangeHookParams } from '../types/hook';
|
import { Hooks, ViewportChangeHookParams } from '../types/hook';
|
||||||
import { ITEM_TYPE, ShapeStyle, SHAPE_TYPE } from '../types/item';
|
import { ITEM_TYPE, ShapeStyle, SHAPE_TYPE } from '../types/item';
|
||||||
@ -250,6 +250,7 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
changes: GraphChange<NodeModelData, EdgeModelData>[];
|
changes: GraphChange<NodeModelData, EdgeModelData>[];
|
||||||
graphCore: GraphCore;
|
graphCore: GraphCore;
|
||||||
theme: ThemeSpecification;
|
theme: ThemeSpecification;
|
||||||
|
animate?: boolean;
|
||||||
upsertAncestors?: boolean;
|
upsertAncestors?: boolean;
|
||||||
}>({ name: 'itemchange' }),
|
}>({ name: 'itemchange' }),
|
||||||
render: new Hook<{
|
render: new Hook<{
|
||||||
@ -259,7 +260,11 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
}>({
|
}>({
|
||||||
name: 'render',
|
name: 'render',
|
||||||
}),
|
}),
|
||||||
layout: new Hook<{ graphCore: GraphCore }>({ name: 'layout' }),
|
layout: new Hook<{
|
||||||
|
graphCore: GraphCore;
|
||||||
|
options?: LayoutOptions;
|
||||||
|
animate?: boolean;
|
||||||
|
}>({ name: 'layout' }),
|
||||||
viewportchange: new Hook<ViewportChangeHookParams>({ name: 'viewport' }),
|
viewportchange: new Hook<ViewportChangeHookParams>({ name: 'viewport' }),
|
||||||
modechange: new Hook<{ mode: string }>({ name: 'modechange' }),
|
modechange: new Hook<{ mode: string }>({ name: 'modechange' }),
|
||||||
behaviorchange: new Hook<{
|
behaviorchange: new Hook<{
|
||||||
@ -309,6 +314,12 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
transient: Canvas;
|
transient: Canvas;
|
||||||
};
|
};
|
||||||
}>({ name: 'init' }),
|
}>({ name: 'init' }),
|
||||||
|
treecollapseexpand: new Hook<{
|
||||||
|
ids: ID[];
|
||||||
|
animate: boolean;
|
||||||
|
action: 'collapse' | 'expand';
|
||||||
|
graphCore: GraphCore;
|
||||||
|
}>({ name: 'treecollapseexpand' }),
|
||||||
destroy: new Hook<{}>({ name: 'destroy' }),
|
destroy: new Hook<{}>({ name: 'destroy' }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -355,7 +366,7 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
* @returns
|
* @returns
|
||||||
* @group Data
|
* @group Data
|
||||||
*/
|
*/
|
||||||
public async read(data: GraphData) {
|
public async read(data: DataConfig) {
|
||||||
this.hooks.datachange.emit({ data, type: 'replace' });
|
this.hooks.datachange.emit({ data, type: 'replace' });
|
||||||
const emitRender = async () => {
|
const emitRender = async () => {
|
||||||
this.hooks.render.emit({
|
this.hooks.render.emit({
|
||||||
@ -387,7 +398,7 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
* @group Data
|
* @group Data
|
||||||
*/
|
*/
|
||||||
public async changeData(
|
public async changeData(
|
||||||
data: GraphData,
|
data: DataConfig,
|
||||||
type: 'replace' | 'mergeReplace' = 'mergeReplace',
|
type: 'replace' | 'mergeReplace' = 'mergeReplace',
|
||||||
) {
|
) {
|
||||||
this.hooks.datachange.emit({ data, type });
|
this.hooks.datachange.emit({ data, type });
|
||||||
@ -1028,9 +1039,21 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
||||||
>,
|
>,
|
||||||
upsertAncestors?: boolean,
|
upsertAncestors?: boolean,
|
||||||
|
disableAnimate: boolean = false,
|
||||||
|
callback?: (
|
||||||
|
model: NodeModel | EdgeModel | ComboModel,
|
||||||
|
canceled?: boolean,
|
||||||
|
) => void,
|
||||||
stack?: boolean,
|
stack?: boolean,
|
||||||
) {
|
) {
|
||||||
return this.updatePosition('node', models, upsertAncestors, stack);
|
return this.updatePosition(
|
||||||
|
'node',
|
||||||
|
models,
|
||||||
|
upsertAncestors,
|
||||||
|
disableAnimate,
|
||||||
|
callback,
|
||||||
|
stack,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1048,9 +1071,18 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
||||||
>,
|
>,
|
||||||
upsertAncestors?: boolean,
|
upsertAncestors?: boolean,
|
||||||
|
disableAnimate: boolean = false,
|
||||||
|
callback?: (model: NodeModel | EdgeModel | ComboModel) => void,
|
||||||
stack?: boolean,
|
stack?: boolean,
|
||||||
) {
|
) {
|
||||||
return this.updatePosition('combo', models, upsertAncestors, stack);
|
return this.updatePosition(
|
||||||
|
'combo',
|
||||||
|
models,
|
||||||
|
upsertAncestors,
|
||||||
|
disableAnimate,
|
||||||
|
callback,
|
||||||
|
stack,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updatePosition(
|
private updatePosition(
|
||||||
@ -1061,6 +1093,11 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
||||||
>,
|
>,
|
||||||
upsertAncestors?: boolean,
|
upsertAncestors?: boolean,
|
||||||
|
disableAnimate: boolean = false,
|
||||||
|
callback?: (
|
||||||
|
model: NodeModel | EdgeModel | ComboModel,
|
||||||
|
canceled?: boolean,
|
||||||
|
) => void,
|
||||||
stack?: boolean,
|
stack?: boolean,
|
||||||
) {
|
) {
|
||||||
const modelArr = isArray(models) ? models : [models];
|
const modelArr = isArray(models) ? models : [models];
|
||||||
@ -1075,6 +1112,8 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
theme: specification,
|
theme: specification,
|
||||||
upsertAncestors,
|
upsertAncestors,
|
||||||
action: 'updatePosition',
|
action: 'updatePosition',
|
||||||
|
animate: !disableAnimate,
|
||||||
|
callback,
|
||||||
});
|
});
|
||||||
this.emit('afteritemchange', {
|
this.emit('afteritemchange', {
|
||||||
type,
|
type,
|
||||||
@ -1105,13 +1144,13 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
* @returns
|
* @returns
|
||||||
* @group Item
|
* @group Item
|
||||||
*/
|
*/
|
||||||
public showItem(ids: ID | ID[], disableAniamte?: boolean) {
|
public showItem(ids: ID | ID[], disableAnimate: boolean = false) {
|
||||||
const idArr = isArray(ids) ? ids : [ids];
|
const idArr = isArray(ids) ? ids : [ids];
|
||||||
this.hooks.itemvisibilitychange.emit({
|
this.hooks.itemvisibilitychange.emit({
|
||||||
ids: idArr as ID[],
|
ids: idArr as ID[],
|
||||||
value: true,
|
value: true,
|
||||||
graphCore: this.dataController.graphCore,
|
graphCore: this.dataController.graphCore,
|
||||||
animate: !disableAniamte,
|
animate: !disableAnimate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -1120,13 +1159,13 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
* @returns
|
* @returns
|
||||||
* @group Item
|
* @group Item
|
||||||
*/
|
*/
|
||||||
public hideItem(ids: ID | ID[], disableAniamte?: boolean) {
|
public hideItem(ids: ID | ID[], disableAnimate: boolean = false) {
|
||||||
const idArr = isArray(ids) ? ids : [ids];
|
const idArr = isArray(ids) ? ids : [ids];
|
||||||
this.hooks.itemvisibilitychange.emit({
|
this.hooks.itemvisibilitychange.emit({
|
||||||
ids: idArr as ID[],
|
ids: idArr as ID[],
|
||||||
value: false,
|
value: false,
|
||||||
graphCore: this.dataController.graphCore,
|
graphCore: this.dataController.graphCore,
|
||||||
animate: !disableAniamte,
|
animate: !disableAnimate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1364,7 +1403,10 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
/**
|
/**
|
||||||
* Layout the graph (with current configurations if cfg is not assigned).
|
* Layout the graph (with current configurations if cfg is not assigned).
|
||||||
*/
|
*/
|
||||||
public async layout(options?: LayoutOptions) {
|
public async layout(
|
||||||
|
options?: LayoutOptions,
|
||||||
|
disableAnimate: boolean = false,
|
||||||
|
) {
|
||||||
const { graphCore } = this.dataController;
|
const { graphCore } = this.dataController;
|
||||||
const formattedOptions = {
|
const formattedOptions = {
|
||||||
...this.getSpecification().layout,
|
...this.getSpecification().layout,
|
||||||
@ -1400,6 +1442,7 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
await this.hooks.layout.emitLinearAsync({
|
await this.hooks.layout.emitLinearAsync({
|
||||||
graphCore,
|
graphCore,
|
||||||
options: formattedOptions,
|
options: formattedOptions,
|
||||||
|
animate: !disableAnimate,
|
||||||
});
|
});
|
||||||
this.emit('afterlayout');
|
this.emit('afterlayout');
|
||||||
}
|
}
|
||||||
@ -1653,6 +1696,47 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
|||||||
return this.itemController.getTransient(String(id));
|
return this.itemController.getTransient(String(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapse sub tree(s).
|
||||||
|
* @param ids Root id(s) of the sub trees.
|
||||||
|
* @param disableAnimate Whether disable the animations for this operation.
|
||||||
|
* @param stack Whether push this operation to stack.
|
||||||
|
* @returns
|
||||||
|
* @group Tree
|
||||||
|
*/
|
||||||
|
public collapse(
|
||||||
|
ids: ID | ID[],
|
||||||
|
disableAnimate: boolean = false,
|
||||||
|
stack?: boolean,
|
||||||
|
) {
|
||||||
|
this.hooks.treecollapseexpand.emit({
|
||||||
|
ids: isArray(ids) ? ids : [ids],
|
||||||
|
action: 'collapse',
|
||||||
|
animate: !disableAnimate,
|
||||||
|
graphCore: this.dataController.graphCore,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Expand sub tree(s).
|
||||||
|
* @param ids Root id(s) of the sub trees.
|
||||||
|
* @param disableAnimate Whether disable the animations for this operation.
|
||||||
|
* @param stack Whether push this operation to stack.
|
||||||
|
* @returns
|
||||||
|
* @group Tree
|
||||||
|
*/
|
||||||
|
public expand(
|
||||||
|
ids: ID | ID[],
|
||||||
|
disableAnimate: boolean = false,
|
||||||
|
stack?: boolean,
|
||||||
|
) {
|
||||||
|
this.hooks.treecollapseexpand.emit({
|
||||||
|
ids: isArray(ids) ? ids : [ids],
|
||||||
|
action: 'expand',
|
||||||
|
animate: !disableAnimate,
|
||||||
|
graphCore: this.dataController.graphCore,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the graph instance and remove the related canvases.
|
* Destroy the graph instance and remove the related canvases.
|
||||||
* @returns
|
* @returns
|
||||||
|
106
packages/g6/src/stdlib/behavior/collapse-expand-tree.ts
Normal file
106
packages/g6/src/stdlib/behavior/collapse-expand-tree.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { Behavior } from '../../types/behavior';
|
||||||
|
import { IG6GraphEvent } from '../../types/event';
|
||||||
|
|
||||||
|
const ALLOWED_TRIGGERS = ['click', 'dblclick'] as const;
|
||||||
|
type Trigger = (typeof ALLOWED_TRIGGERS)[number];
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
/**
|
||||||
|
* The key to pressed with mouse click to apply multiple selection.
|
||||||
|
* Defaults to `"shift"`.
|
||||||
|
* Could be "shift", "ctrl", "alt", or "meta".
|
||||||
|
*/
|
||||||
|
trigger: Trigger;
|
||||||
|
/**
|
||||||
|
* The event name to trigger when select/unselect an item.
|
||||||
|
*/
|
||||||
|
eventName: string;
|
||||||
|
/**
|
||||||
|
* Whether disable the collapse / expand animation triggered by this behavior.
|
||||||
|
*/
|
||||||
|
disableAnimate: boolean;
|
||||||
|
/**
|
||||||
|
* Whether allow the behavior happen on the current item.
|
||||||
|
*/
|
||||||
|
shouldBegin: (event: IG6GraphEvent) => boolean;
|
||||||
|
/**
|
||||||
|
* Whether to update item state.
|
||||||
|
* If it returns false, you may probably listen to `eventName` and
|
||||||
|
* manage states or data manually
|
||||||
|
*/
|
||||||
|
shouldUpdate: (event: IG6GraphEvent) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_OPTIONS: Options = {
|
||||||
|
trigger: 'click',
|
||||||
|
eventName: '',
|
||||||
|
disableAnimate: false,
|
||||||
|
shouldBegin: () => true,
|
||||||
|
shouldUpdate: () => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class CollapseExpandTree extends Behavior {
|
||||||
|
options: Options;
|
||||||
|
private timeout: NodeJS.Timeout = undefined;
|
||||||
|
|
||||||
|
constructor(options: Partial<Options>) {
|
||||||
|
super(Object.assign({}, DEFAULT_OPTIONS, options));
|
||||||
|
// Validate options
|
||||||
|
if (options.trigger && !ALLOWED_TRIGGERS.includes(options.trigger)) {
|
||||||
|
console.warn(
|
||||||
|
`G6: Invalid trigger option "${options.trigger}" for collapse-expand-tree behavior!`,
|
||||||
|
);
|
||||||
|
this.options.trigger = DEFAULT_OPTIONS.trigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getEvents = () => {
|
||||||
|
return this.options.trigger === 'dblclick'
|
||||||
|
? {
|
||||||
|
'node:dblclick': this.onClick,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
'node:click': this.onClickBesideDblClick,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
public onClickBesideDblClick(event: IG6GraphEvent) {
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.timeout = undefined;
|
||||||
|
this.onClick(event);
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClick(event: IG6GraphEvent) {
|
||||||
|
if (!this.options.shouldBegin(event)) return;
|
||||||
|
const { itemId, itemType } = event;
|
||||||
|
const { disableAnimate } = this.options;
|
||||||
|
|
||||||
|
const model = this.graph.getNodeData(itemId);
|
||||||
|
if (!model) {
|
||||||
|
console.warn(`Node with id ${itemId} is not exist`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let action = 'expand';
|
||||||
|
if (model.data.collapsed) {
|
||||||
|
this.graph.expand(itemId, disableAnimate);
|
||||||
|
} else {
|
||||||
|
this.graph.collapse(itemId, disableAnimate);
|
||||||
|
action = 'collapse';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit an event.
|
||||||
|
if (this.options.eventName) {
|
||||||
|
this.graph.emit(this.options.eventName, {
|
||||||
|
action,
|
||||||
|
itemId,
|
||||||
|
itemType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { registry as layoutRegistry } from '@antv/layout';
|
import { registry as layoutRegistry } from '@antv/layout';
|
||||||
|
import Hierarchy from '@antv/hierarchy';
|
||||||
import { Lib } from '../types/stdlib';
|
import { Lib } from '../types/stdlib';
|
||||||
import ActivateRelations from './behavior/activate-relations';
|
import ActivateRelations from './behavior/activate-relations';
|
||||||
import BrushSelect from './behavior/brush-select';
|
import BrushSelect from './behavior/brush-select';
|
||||||
@ -30,6 +31,7 @@ import TrackCanvas3D from './behavior/track-canvas-3d';
|
|||||||
import OrbitCanvas3D from './behavior/orbit-canvas-3d';
|
import OrbitCanvas3D from './behavior/orbit-canvas-3d';
|
||||||
import HoverActivate from './behavior/hover-activate';
|
import HoverActivate from './behavior/hover-activate';
|
||||||
import CollapseExpandCombo from './behavior/collapse-expand-combo';
|
import CollapseExpandCombo from './behavior/collapse-expand-combo';
|
||||||
|
import CollapseExpandTree from './behavior/collapse-expand-tree';
|
||||||
import { CubicEdge } from './item/edge/cubic';
|
import { CubicEdge } from './item/edge/cubic';
|
||||||
import { CubicHorizonEdge } from './item/edge/cubic-horizon';
|
import { CubicHorizonEdge } from './item/edge/cubic-horizon';
|
||||||
import { CubicVerticalEdge } from './item/edge/cubic-vertical';
|
import { CubicVerticalEdge } from './item/edge/cubic-vertical';
|
||||||
@ -48,7 +50,10 @@ const stdLib = {
|
|||||||
spec: SpecThemeSolver,
|
spec: SpecThemeSolver,
|
||||||
subject: SubjectThemeSolver,
|
subject: SubjectThemeSolver,
|
||||||
},
|
},
|
||||||
layouts: layoutRegistry,
|
layouts: {
|
||||||
|
...layoutRegistry,
|
||||||
|
...Hierarchy,
|
||||||
|
},
|
||||||
behaviors: {
|
behaviors: {
|
||||||
'activate-relations': ActivateRelations,
|
'activate-relations': ActivateRelations,
|
||||||
'drag-canvas': DragCanvas,
|
'drag-canvas': DragCanvas,
|
||||||
@ -57,6 +62,7 @@ const stdLib = {
|
|||||||
'drag-node': DragNode,
|
'drag-node': DragNode,
|
||||||
'drag-combo': DragCombo,
|
'drag-combo': DragCombo,
|
||||||
'collapse-expand-combo': CollapseExpandCombo,
|
'collapse-expand-combo': CollapseExpandCombo,
|
||||||
|
'collapse-expand-tree': CollapseExpandTree,
|
||||||
'click-select': ClickSelect,
|
'click-select': ClickSelect,
|
||||||
'brush-select': BrushSelect,
|
'brush-select': BrushSelect,
|
||||||
'lasso-select': LassoSelect,
|
'lasso-select': LassoSelect,
|
||||||
|
@ -35,8 +35,6 @@ export default class Grid extends Base {
|
|||||||
public init(graph: IGraph) {
|
public init(graph: IGraph) {
|
||||||
super.init(graph);
|
super.init(graph);
|
||||||
const minZoom = graph.getZoom();
|
const minZoom = graph.getZoom();
|
||||||
// console.log('minZoom', minZoom);
|
|
||||||
// console.log('graph', graph.canvas);
|
|
||||||
const graphContainer = graph.container;
|
const graphContainer = graph.container;
|
||||||
const canvas = this.canvas || graphContainer.firstChild.nextSibling;
|
const canvas = this.canvas || graphContainer.firstChild.nextSibling;
|
||||||
const [width, height] = graph.getSize();
|
const [width, height] = graph.getSize();
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Graph as GraphLib } from '@antv/graphlib';
|
import { Graph as GraphLib, TreeData } from '@antv/graphlib';
|
||||||
import { ComboUserModel } from './combo';
|
import { ComboUserModel } from './combo';
|
||||||
import { NodeDisplayModelData, NodeModelData, NodeUserModel } from './node';
|
import { NodeDisplayModelData, NodeModelData, NodeUserModel } from './node';
|
||||||
import { EdgeDisplayModelData, EdgeModelData, EdgeUserModel } from './edge';
|
import { EdgeDisplayModelData, EdgeModelData, EdgeUserModel } from './edge';
|
||||||
|
import { NodeUserModelData } from './node';
|
||||||
|
|
||||||
export interface GraphData {
|
export interface GraphData {
|
||||||
nodes?: NodeUserModel[];
|
nodes?: NodeUserModel[];
|
||||||
@ -9,16 +10,26 @@ export interface GraphData {
|
|||||||
combos?: ComboUserModel[];
|
combos?: ComboUserModel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InlineDataConfig {
|
export interface InlineGraphDataConfig {
|
||||||
type: 'inline';
|
type: 'graphData';
|
||||||
value: GraphData;
|
value: GraphData;
|
||||||
}
|
}
|
||||||
|
export interface InlineTreeDataConfig {
|
||||||
|
type: 'treeData';
|
||||||
|
value: TreeData<NodeUserModelData> | TreeData<NodeUserModelData>[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface FetchDataConfig {
|
export interface FetchDataConfig {
|
||||||
type: 'fetch';
|
type: 'fetch';
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DataConfig =
|
||||||
|
| GraphData
|
||||||
|
| InlineGraphDataConfig
|
||||||
|
| InlineTreeDataConfig
|
||||||
|
| FetchDataConfig;
|
||||||
|
|
||||||
export type GraphCore = GraphLib<NodeModelData, EdgeModelData>;
|
export type GraphCore = GraphLib<NodeModelData, EdgeModelData>;
|
||||||
export type DisplayGraphCore = GraphLib<
|
export type DisplayGraphCore = GraphLib<
|
||||||
NodeDisplayModelData,
|
NodeDisplayModelData,
|
||||||
|
@ -232,6 +232,11 @@ export interface IGraph<
|
|||||||
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
||||||
>,
|
>,
|
||||||
upsertAncestors?: boolean,
|
upsertAncestors?: boolean,
|
||||||
|
disableAnimate?: boolean,
|
||||||
|
callback?: (
|
||||||
|
model: NodeModel | EdgeModel | ComboModel,
|
||||||
|
canceled?: boolean,
|
||||||
|
) => void,
|
||||||
stack?: boolean,
|
stack?: boolean,
|
||||||
) => NodeModel | ComboModel | NodeModel[] | ComboModel[];
|
) => NodeModel | ComboModel | NodeModel[] | ComboModel[];
|
||||||
|
|
||||||
@ -249,6 +254,8 @@ export interface IGraph<
|
|||||||
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
ComboUserModel | Partial<NodeUserModel>[] | Partial<ComboUserModel>[]
|
||||||
>,
|
>,
|
||||||
upsertAncestors?: boolean,
|
upsertAncestors?: boolean,
|
||||||
|
disableAnimate?: boolean,
|
||||||
|
callback?: (model: NodeModel | EdgeModel | ComboModel) => void,
|
||||||
stack?: boolean,
|
stack?: boolean,
|
||||||
) => NodeModel | ComboModel | NodeModel[] | ComboModel[];
|
) => NodeModel | ComboModel | NodeModel[] | ComboModel[];
|
||||||
|
|
||||||
@ -444,14 +451,14 @@ export interface IGraph<
|
|||||||
* @returns
|
* @returns
|
||||||
* @group Data
|
* @group Data
|
||||||
*/
|
*/
|
||||||
showItem: (ids: ID | ID[], disableAniamte?: boolean) => void;
|
showItem: (ids: ID | ID[], disableAnimate?: boolean) => void;
|
||||||
/**
|
/**
|
||||||
* Hide the item(s).
|
* Hide the item(s).
|
||||||
* @param ids the item id(s) to be hidden
|
* @param ids the item id(s) to be hidden
|
||||||
* @returns
|
* @returns
|
||||||
* @group Item
|
* @group Item
|
||||||
*/
|
*/
|
||||||
hideItem: (ids: ID | ID[], disableAniamte?: boolean) => void;
|
hideItem: (ids: ID | ID[], disableAnimate?: boolean) => void;
|
||||||
/**
|
/**
|
||||||
* Make the item(s) to the front.
|
* Make the item(s) to the front.
|
||||||
* @param ids the item id(s) to front
|
* @param ids the item id(s) to front
|
||||||
@ -543,7 +550,7 @@ export interface IGraph<
|
|||||||
/**
|
/**
|
||||||
* Layout the graph (with current configurations if cfg is not assigned).
|
* Layout the graph (with current configurations if cfg is not assigned).
|
||||||
*/
|
*/
|
||||||
layout: (options?: LayoutOptions) => Promise<void>;
|
layout: (options?: LayoutOptions, disableAnimate?: boolean) => Promise<void>;
|
||||||
stopLayout: () => void;
|
stopLayout: () => void;
|
||||||
|
|
||||||
// ===== interaction =====
|
// ===== interaction =====
|
||||||
@ -627,4 +634,24 @@ export interface IGraph<
|
|||||||
type: string;
|
type: string;
|
||||||
[cfgName: string]: unknown;
|
[cfgName: string]: unknown;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
|
// ===== tree operations =====
|
||||||
|
/**
|
||||||
|
* Collapse sub tree(s).
|
||||||
|
* @param ids Root id(s) of the sub trees.
|
||||||
|
* @param disableAnimate Whether disable the animations for this operation.
|
||||||
|
* @param stack Whether push this operation to stack.
|
||||||
|
* @returns
|
||||||
|
* @group Tree
|
||||||
|
*/
|
||||||
|
collapse: (ids: ID | ID[], disableAnimate?: boolean, stack?: boolean) => void;
|
||||||
|
/**
|
||||||
|
* Expand sub tree(s).
|
||||||
|
* @param ids Root id(s) of the sub trees.
|
||||||
|
* @param disableAnimate Whether disable the animations for this operation.
|
||||||
|
* @param stack Whether push this operation to stack.
|
||||||
|
* @returns
|
||||||
|
* @group Tree
|
||||||
|
*/
|
||||||
|
expand: (ids: ID | ID[], disableAnimate?: boolean, stack?: boolean) => void;
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,14 @@ import { Canvas } from '@antv/g';
|
|||||||
import { GraphChange, ID } from '@antv/graphlib';
|
import { GraphChange, ID } from '@antv/graphlib';
|
||||||
import { CameraAnimationOptions } from './animate';
|
import { CameraAnimationOptions } from './animate';
|
||||||
import { BehaviorOptionsOf } from './behavior';
|
import { BehaviorOptionsOf } from './behavior';
|
||||||
import { DataChangeType, GraphCore, GraphData } from './data';
|
import { DataChangeType, DataConfig, GraphCore } from './data';
|
||||||
import { EdgeModelData } from './edge';
|
import { EdgeModel, EdgeModelData } from './edge';
|
||||||
import { ITEM_TYPE, ShapeStyle, SHAPE_TYPE } from './item';
|
import { ITEM_TYPE, ShapeStyle, SHAPE_TYPE } from './item';
|
||||||
import { LayoutOptions } from './layout';
|
import { LayoutOptions } from './layout';
|
||||||
import { NodeModelData } from './node';
|
import { NodeModel, NodeModelData } from './node';
|
||||||
import { ThemeSpecification } from './theme';
|
import { ThemeSpecification } from './theme';
|
||||||
import { GraphTransformOptions } from './view';
|
import { GraphTransformOptions } from './view';
|
||||||
|
import { ComboModel } from './combo';
|
||||||
|
|
||||||
export interface IHook<T> {
|
export interface IHook<T> {
|
||||||
name: string;
|
name: string;
|
||||||
@ -35,7 +36,7 @@ export interface Hooks {
|
|||||||
// data
|
// data
|
||||||
datachange: IHook<{
|
datachange: IHook<{
|
||||||
type: DataChangeType;
|
type: DataChangeType;
|
||||||
data: GraphData;
|
data: DataConfig;
|
||||||
}>;
|
}>;
|
||||||
itemchange: IHook<{
|
itemchange: IHook<{
|
||||||
type: ITEM_TYPE;
|
type: ITEM_TYPE;
|
||||||
@ -43,14 +44,20 @@ export interface Hooks {
|
|||||||
graphCore: GraphCore;
|
graphCore: GraphCore;
|
||||||
theme: ThemeSpecification;
|
theme: ThemeSpecification;
|
||||||
upsertAncestors?: boolean;
|
upsertAncestors?: boolean;
|
||||||
|
animate?: boolean;
|
||||||
action?: 'updatePosition';
|
action?: 'updatePosition';
|
||||||
|
callback?: (model: NodeModel | EdgeModel | ComboModel) => void;
|
||||||
}>;
|
}>;
|
||||||
render: IHook<{
|
render: IHook<{
|
||||||
graphCore: GraphCore;
|
graphCore: GraphCore;
|
||||||
theme: ThemeSpecification;
|
theme: ThemeSpecification;
|
||||||
transientCanvas: Canvas;
|
transientCanvas: Canvas;
|
||||||
}>; // TODO: define param template
|
}>; // TODO: define param template
|
||||||
layout: IHook<{ graphCore: GraphCore; options?: LayoutOptions }>; // TODO: define param template
|
layout: IHook<{
|
||||||
|
graphCore: GraphCore;
|
||||||
|
options?: LayoutOptions;
|
||||||
|
animate?: boolean;
|
||||||
|
}>; // TODO: define param template
|
||||||
// 'updatelayout': IHook<any>; // TODO: define param template
|
// 'updatelayout': IHook<any>; // TODO: define param template
|
||||||
modechange: IHook<{ mode: string }>;
|
modechange: IHook<{ mode: string }>;
|
||||||
behaviorchange: IHook<{
|
behaviorchange: IHook<{
|
||||||
@ -101,6 +108,11 @@ export interface Hooks {
|
|||||||
transient: Canvas;
|
transient: Canvas;
|
||||||
};
|
};
|
||||||
}>;
|
}>;
|
||||||
|
treecollapseexpand: IHook<{
|
||||||
|
ids: ID[];
|
||||||
|
action: 'collapse' | 'expand';
|
||||||
|
graphCore: GraphCore;
|
||||||
|
animate?: boolean;
|
||||||
|
}>;
|
||||||
destroy: IHook<{}>;
|
destroy: IHook<{}>;
|
||||||
// TODO: more timecycles here
|
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ import {
|
|||||||
NodeShapeMap,
|
NodeShapeMap,
|
||||||
NodeUserModel,
|
NodeUserModel,
|
||||||
} from './node';
|
} from './node';
|
||||||
|
import { ComboStyleSet, EdgeStyleSet, NodeStyleSet } from './theme';
|
||||||
|
|
||||||
export type GShapeStyle = CircleStyleProps &
|
export type GShapeStyle = CircleStyleProps &
|
||||||
RectStyleProps &
|
RectStyleProps &
|
||||||
@ -248,6 +249,8 @@ export interface IItem {
|
|||||||
displayModel: ItemDisplayModel,
|
displayModel: ItemDisplayModel,
|
||||||
diffData?: { previous: ItemModelData; current: ItemModelData },
|
diffData?: { previous: ItemModelData; current: ItemModelData },
|
||||||
diffState?: { previous: State[]; current: State[] },
|
diffState?: { previous: State[]; current: State[] },
|
||||||
|
animate?: boolean,
|
||||||
|
onfinish?: Function,
|
||||||
) => void;
|
) => void;
|
||||||
/**
|
/**
|
||||||
* Updates the shapes.
|
* Updates the shapes.
|
||||||
@ -256,7 +259,14 @@ export interface IItem {
|
|||||||
update: (
|
update: (
|
||||||
model: ItemModel,
|
model: ItemModel,
|
||||||
diffData: { previous: ItemModelData; current: ItemModelData },
|
diffData: { previous: ItemModelData; current: ItemModelData },
|
||||||
isUpdate?: boolean,
|
isReplace?: boolean,
|
||||||
|
itemTheme?: {
|
||||||
|
styles: NodeStyleSet | EdgeStyleSet | ComboStyleSet;
|
||||||
|
lodStrategy: LodStrategyObj;
|
||||||
|
},
|
||||||
|
onlyMove?: boolean,
|
||||||
|
animate?: boolean,
|
||||||
|
onfinish?: Function,
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -269,6 +279,7 @@ export interface IItem {
|
|||||||
updatePosition: (
|
updatePosition: (
|
||||||
displayModel: ItemDisplayModel,
|
displayModel: ItemDisplayModel,
|
||||||
diffData?: { previous: ItemModelData; current: ItemModelData },
|
diffData?: { previous: ItemModelData; current: ItemModelData },
|
||||||
|
animate?: boolean,
|
||||||
onfinish?: Function,
|
onfinish?: Function,
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
|
@ -45,6 +45,10 @@ export interface NodeUserModelData extends PlainObject {
|
|||||||
* Reserved for combo.
|
* Reserved for combo.
|
||||||
*/
|
*/
|
||||||
parentId?: ID;
|
parentId?: ID;
|
||||||
|
/**
|
||||||
|
* Whether to be a root at when used as a tree.
|
||||||
|
*/
|
||||||
|
isRoot?: boolean;
|
||||||
/**
|
/**
|
||||||
* The icon to show on the node.
|
* The icon to show on the node.
|
||||||
* More styles should be configured in node mapper.
|
* More styles should be configured in node mapper.
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
import { Canvas } from '@antv/g';
|
import { Canvas } from '@antv/g';
|
||||||
import { AnimateCfg } from './animate';
|
import { AnimateCfg } from './animate';
|
||||||
import { Point } from './common';
|
import { Point } from './common';
|
||||||
import {
|
import { DataConfig, TransformerFn } from './data';
|
||||||
FetchDataConfig,
|
|
||||||
GraphData,
|
|
||||||
InlineDataConfig,
|
|
||||||
TransformerFn,
|
|
||||||
} from './data';
|
|
||||||
import {
|
import {
|
||||||
EdgeDisplayModel,
|
EdgeDisplayModel,
|
||||||
EdgeEncode,
|
EdgeEncode,
|
||||||
@ -36,7 +31,6 @@ export interface Specification<
|
|||||||
B extends BehaviorRegistry,
|
B extends BehaviorRegistry,
|
||||||
T extends ThemeRegistry,
|
T extends ThemeRegistry,
|
||||||
> {
|
> {
|
||||||
type: 'graph' | 'tree';
|
|
||||||
container?: string | HTMLElement;
|
container?: string | HTMLElement;
|
||||||
backgroundCanvas?: Canvas;
|
backgroundCanvas?: Canvas;
|
||||||
canvas?: Canvas;
|
canvas?: Canvas;
|
||||||
@ -61,7 +55,7 @@ export interface Specification<
|
|||||||
optimizeThreshold?: number;
|
optimizeThreshold?: number;
|
||||||
|
|
||||||
/** data */
|
/** data */
|
||||||
data: GraphData | InlineDataConfig | FetchDataConfig; // TODO: more
|
data?: DataConfig;
|
||||||
transform?:
|
transform?:
|
||||||
| string[]
|
| string[]
|
||||||
| {
|
| {
|
||||||
|
@ -248,7 +248,7 @@ const runAnimateGroupOnShapes = (
|
|||||||
maxDurationIdx = i;
|
maxDurationIdx = i;
|
||||||
}
|
}
|
||||||
if (animation) {
|
if (animation) {
|
||||||
animation.oncancel = () => {
|
animation.onManualCancel = () => {
|
||||||
hasCanceled = true;
|
hasCanceled = true;
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
};
|
};
|
||||||
@ -293,10 +293,37 @@ const runAnimateOnShape = (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (JSON.stringify(animateArr[0]) === JSON.stringify(animateArr[1])) return;
|
if (!checkFrames(animateArr, shape)) return;
|
||||||
return shape.animate(animateArr, animateConfig);
|
return shape.animate(animateArr, animateConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check and format the frames. If the frames are same, return false. If frames contains undefined x or y, format them.
|
||||||
|
* @param frames
|
||||||
|
* @param shape
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const checkFrames = (frames, shape) => {
|
||||||
|
if (JSON.stringify(frames[0]) === JSON.stringify(frames[1])) return false;
|
||||||
|
['x', 'y'].forEach((dim) => {
|
||||||
|
if (!frames[0].hasOwnProperty(dim)) return;
|
||||||
|
let val;
|
||||||
|
const formatted = [...frames];
|
||||||
|
if (frames[0][dim] === undefined && frames[0][dim] !== frames[1][dim])
|
||||||
|
val = frames[1][dim];
|
||||||
|
if (frames[1][dim] === undefined && frames[0][dim] !== frames[1][dim])
|
||||||
|
val = frames[1][dim];
|
||||||
|
if (val !== undefined) {
|
||||||
|
shape.style[dim] = val;
|
||||||
|
delete formatted[0][dim];
|
||||||
|
delete formatted[1][dim];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (JSON.stringify(frames[0]) === JSON.stringify(frames[1])) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle shape and group animations.
|
* Handle shape and group animations.
|
||||||
* Should be called after canvas ready and shape appended.
|
* Should be called after canvas ready and shape appended.
|
||||||
@ -318,7 +345,7 @@ export const animateShapes = (
|
|||||||
onAnimatesEnd: Function = () => {},
|
onAnimatesEnd: Function = () => {},
|
||||||
): IAnimation[] => {
|
): IAnimation[] => {
|
||||||
if (!animates?.[timing]) {
|
if (!animates?.[timing]) {
|
||||||
onAnimatesEnd();
|
onAnimatesEnd(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const segmentedTiming =
|
const segmentedTiming =
|
||||||
@ -335,7 +362,7 @@ export const animateShapes = (
|
|||||||
let canceled = false;
|
let canceled = false;
|
||||||
const onfinish = () => {
|
const onfinish = () => {
|
||||||
if (i >= groupKeys.length) {
|
if (i >= groupKeys.length) {
|
||||||
onAnimatesEnd();
|
!canceled && onAnimatesEnd(canceled);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const groupAnimations = runAnimateGroupOnShapes(
|
const groupAnimations = runAnimateGroupOnShapes(
|
||||||
@ -345,7 +372,10 @@ export const animateShapes = (
|
|||||||
mergedStyles,
|
mergedStyles,
|
||||||
timing,
|
timing,
|
||||||
onfinish, // execute next order group
|
onfinish, // execute next order group
|
||||||
() => (canceled = true),
|
() => {
|
||||||
|
canceled = true;
|
||||||
|
onAnimatesEnd(canceled);
|
||||||
|
},
|
||||||
canceled,
|
canceled,
|
||||||
).filter(Boolean);
|
).filter(Boolean);
|
||||||
groupAnimations.forEach((animation) => {
|
groupAnimations.forEach((animation) => {
|
||||||
@ -429,8 +459,9 @@ export const fadeOut = (id, shape, hiddenShape, animateConfig) => {
|
|||||||
* Make the animation to the end frame and clear it from the target shape.
|
* Make the animation to the end frame and clear it from the target shape.
|
||||||
* @param animation
|
* @param animation
|
||||||
*/
|
*/
|
||||||
export const stopAnimate = (animation) => {
|
export const stopAnimate = (animation: IAnimation): Promise<any> => {
|
||||||
const timing = animation.effect.getTiming();
|
const timing = animation.effect.getTiming();
|
||||||
animation.currentTime = Number(timing.duration) + Number(timing.delay || 0);
|
animation.currentTime = Number(timing.duration) + Number(timing.delay || 0);
|
||||||
animation.cancel();
|
animation.finish();
|
||||||
|
return animation.finished;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
import { NodeUserModel } from 'types';
|
import { NodeUserModel } from 'types';
|
||||||
import { IGraph } from '../types/graph';
|
import { IGraph } from '../types/graph';
|
||||||
import { GraphCore } from '../types/data';
|
import { GraphCore, GraphData } from '../types/data';
|
||||||
|
import { TreeData } from '@antv/graphlib';
|
||||||
|
import { NodeUserModelData } from 'types/node';
|
||||||
|
import { isArray } from '@antv/util';
|
||||||
|
import {
|
||||||
|
depthFirstSearch,
|
||||||
|
breadthFirstSearch,
|
||||||
|
connectedComponent,
|
||||||
|
} from '@antv/algorithm';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deconstruct data and distinguish nodes and combos from graphcore data.
|
* Deconstruct data and distinguish nodes and combos from graphcore data.
|
||||||
@ -35,19 +43,30 @@ export const graphCoreTreeDfs = (
|
|||||||
nodes: NodeUserModel[],
|
nodes: NodeUserModel[],
|
||||||
fn,
|
fn,
|
||||||
mode: 'TB' | 'BT' = 'TB',
|
mode: 'TB' | 'BT' = 'TB',
|
||||||
|
treeKey = 'combo',
|
||||||
|
stopFns: {
|
||||||
|
stopBranchFn?: (node: NodeUserModel) => boolean;
|
||||||
|
stopAllFn?: (node: NodeUserModel) => boolean;
|
||||||
|
} = {},
|
||||||
) => {
|
) => {
|
||||||
if (!nodes?.length) return;
|
if (!nodes?.length) return;
|
||||||
nodes.forEach((node) => {
|
const { stopBranchFn, stopAllFn } = stopFns;
|
||||||
if (!graphCore.hasNode(node.id)) return;
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
const node = nodes[i];
|
||||||
|
if (!graphCore.hasNode(node.id)) continue;
|
||||||
|
if (stopBranchFn?.(node)) continue; // Stop this branch
|
||||||
|
if (stopAllFn?.(node)) return; // Stop all
|
||||||
if (mode === 'TB') fn(node); // Traverse from top to bottom
|
if (mode === 'TB') fn(node); // Traverse from top to bottom
|
||||||
graphCoreTreeDfs(
|
graphCoreTreeDfs(
|
||||||
graphCore,
|
graphCore,
|
||||||
graphCore.getChildren(node.id, 'combo'),
|
graphCore.getChildren(node.id, treeKey),
|
||||||
fn,
|
fn,
|
||||||
mode,
|
mode,
|
||||||
|
treeKey,
|
||||||
|
stopFns,
|
||||||
);
|
);
|
||||||
if (mode !== 'TB') fn(node); // Traverse from bottom to top
|
if (mode !== 'TB') fn(node); // Traverse from bottom to top
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,3 +195,105 @@ export const validateComboStrucutre = (
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform tree graph data into graph data. Edges from parent-child structure.
|
||||||
|
* @param treeData Tree structured data or an array of it.
|
||||||
|
* @returns Graph formatted data object with nodes, edges and combos.
|
||||||
|
*/
|
||||||
|
export const treeData2GraphData = (
|
||||||
|
treeData: TreeData<NodeUserModelData> | TreeData<NodeUserModelData>[],
|
||||||
|
) => {
|
||||||
|
const graphData = {
|
||||||
|
nodes: [],
|
||||||
|
edges: [],
|
||||||
|
combos: [],
|
||||||
|
};
|
||||||
|
const trees = isArray(treeData) ? treeData : [treeData];
|
||||||
|
trees.forEach((tree) => {
|
||||||
|
traverse(tree, (child) => {
|
||||||
|
graphData.nodes.push({
|
||||||
|
id: child.id,
|
||||||
|
data: child.data,
|
||||||
|
});
|
||||||
|
child.children?.forEach((subChild) => {
|
||||||
|
graphData.edges.push({
|
||||||
|
id: `tree-edge-${child.id}-${subChild.id}`,
|
||||||
|
source: child.id,
|
||||||
|
target: subChild.id,
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return graphData;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform graph data into tree graph data.
|
||||||
|
* @param nodeMap
|
||||||
|
* @param graphData Graph data.
|
||||||
|
* @param propRootIds Ids of root nodes. There should be at least one node for each connected component, or the first node in a connected component will be added to the roots array.
|
||||||
|
* @param algo
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const graphData2TreeData = (
|
||||||
|
nodeMap: { [id: string]: any },
|
||||||
|
graphData: GraphData,
|
||||||
|
propRootIds = [],
|
||||||
|
) => {
|
||||||
|
const trees = [];
|
||||||
|
const connectedComponents = connectedComponent(graphData as any, false);
|
||||||
|
const rootIds = [];
|
||||||
|
const componentsNodeIds = [];
|
||||||
|
connectedComponents.forEach((com, i) => {
|
||||||
|
componentsNodeIds[i] = com.map((node) => node.id);
|
||||||
|
if (propRootIds.length) {
|
||||||
|
const root = componentsNodeIds[0].find((id) => propRootIds.includes(id));
|
||||||
|
rootIds.push(root !== undefined ? root : com[0].id);
|
||||||
|
} else {
|
||||||
|
rootIds.push(com[0].id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rootIds.forEach((id, i) => {
|
||||||
|
nodeMap[id] = { id, children: [] };
|
||||||
|
trees.push(nodeMap[id]);
|
||||||
|
depthFirstSearch(
|
||||||
|
graphData as any,
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
enter: ({ previous, current }) => {
|
||||||
|
if (
|
||||||
|
!previous ||
|
||||||
|
current === id ||
|
||||||
|
!componentsNodeIds[i].includes(current)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
nodeMap[previous] = nodeMap[previous] || {
|
||||||
|
id: previous,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
nodeMap[current] = { id: current, children: [] };
|
||||||
|
nodeMap[previous].children.push(nodeMap[current]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return trees;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Travere a tree data from top to bottom.
|
||||||
|
* @param treeData
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
export const traverse = (treeData, callback) => {
|
||||||
|
callback(treeData);
|
||||||
|
if (treeData.children) {
|
||||||
|
treeData.children.forEach((child) => {
|
||||||
|
if (child) traverse(child, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -83,6 +83,7 @@ type GroupedChanges = {
|
|||||||
EdgeUpdated: EdgeUpdated<EdgeModelData>[];
|
EdgeUpdated: EdgeUpdated<EdgeModelData>[];
|
||||||
EdgeDataUpdated: EdgeDataUpdated<EdgeModelData>[];
|
EdgeDataUpdated: EdgeDataUpdated<EdgeModelData>[];
|
||||||
TreeStructureChanged: TreeStructureChanged[];
|
TreeStructureChanged: TreeStructureChanged[];
|
||||||
|
ComboStructureChanged: TreeStructureChanged[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,6 +105,7 @@ export const getGroupedChanges = (
|
|||||||
EdgeUpdated: [],
|
EdgeUpdated: [],
|
||||||
EdgeDataUpdated: [],
|
EdgeDataUpdated: [],
|
||||||
TreeStructureChanged: [],
|
TreeStructureChanged: [],
|
||||||
|
ComboStructureChanged: [],
|
||||||
};
|
};
|
||||||
changes.forEach((change) => {
|
changes.forEach((change) => {
|
||||||
const { type: changeType } = change;
|
const { type: changeType } = change;
|
||||||
@ -119,7 +121,10 @@ export const getGroupedChanges = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (changeType === 'TreeStructureChanged') {
|
} else if (changeType === 'TreeStructureChanged') {
|
||||||
groupedChanges[changeType].push(change);
|
if (change.treeKey === 'combo')
|
||||||
|
groupedChanges.ComboStructureChanged.push(change);
|
||||||
|
else if (change.treeKey === 'tree')
|
||||||
|
groupedChanges.TreeStructureChanged.push(change);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const { id: oid } = change.value;
|
const { id: oid } = change.value;
|
||||||
|
65
packages/g6/src/util/layout.ts
Normal file
65
packages/g6/src/util/layout.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import Hierarchy from '@antv/hierarchy';
|
||||||
|
import { traverse } from './data';
|
||||||
|
import { TreeGraphData } from '@antv/g6';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judge the direction according to options of a tree layout.
|
||||||
|
* @param type Tree layout type.
|
||||||
|
* @param options Tree layout options.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const isTreeLayoutHorizontal = (type, options) => {
|
||||||
|
const { direction } = options;
|
||||||
|
switch (type) {
|
||||||
|
case 'compactBox':
|
||||||
|
case 'dendrogram':
|
||||||
|
return direction !== 'TB' && direction !== ' BT' && direction !== ' V';
|
||||||
|
case 'indented':
|
||||||
|
return true;
|
||||||
|
case 'mindmap':
|
||||||
|
return direction !== 'V';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout nodes on a single tree.
|
||||||
|
* @param treeData
|
||||||
|
* @param layoutType Tree layout type.
|
||||||
|
* @param layoutOptions Tree layout options.
|
||||||
|
* @param nodeMap
|
||||||
|
* @param nodePositions An array to store the result.
|
||||||
|
* @param begin The begin position for this tree, might be calculated from last tree.
|
||||||
|
* @returns Positions array.
|
||||||
|
*/
|
||||||
|
export const layoutOneTree = (
|
||||||
|
treeData: TreeGraphData,
|
||||||
|
layoutType: string,
|
||||||
|
layoutOptions,
|
||||||
|
nodeMap,
|
||||||
|
nodePositions,
|
||||||
|
begin = [0, 0],
|
||||||
|
) => {
|
||||||
|
const { treeGap = 50 } = layoutOptions;
|
||||||
|
const isHorizontal = isTreeLayoutHorizontal(layoutType, layoutOptions);
|
||||||
|
const layoutData = Hierarchy[layoutType](treeData, layoutOptions);
|
||||||
|
const range = [Infinity, -Infinity];
|
||||||
|
const treeNodeIds = [];
|
||||||
|
traverse(layoutData, (child) => {
|
||||||
|
const { id, x, y } = child;
|
||||||
|
treeNodeIds.push(id);
|
||||||
|
const dim = isHorizontal ? 'y' : 'x';
|
||||||
|
if (range[0] > child[dim]) range[0] = child[dim];
|
||||||
|
if (range[1] < child[dim]) range[1] = child[dim];
|
||||||
|
nodeMap[id].data = { x, y };
|
||||||
|
});
|
||||||
|
const diff = begin[isHorizontal ? 1 : 0] - range[0];
|
||||||
|
treeNodeIds.forEach((id) => {
|
||||||
|
const { x, y } = nodeMap[id].data;
|
||||||
|
nodePositions.push({
|
||||||
|
id,
|
||||||
|
data: isHorizontal ? { x, y: y + diff } : { x: x + diff, y },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
begin[isHorizontal ? 1 : 0] += range[1] + diff + treeGap;
|
||||||
|
return nodePositions;
|
||||||
|
};
|
@ -5,7 +5,6 @@ export default () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
plugins: ['grid'],
|
plugins: ['grid'],
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
|
@ -5,7 +5,6 @@ export default () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,6 @@ export default () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
|
@ -58,7 +58,6 @@ export default () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data,
|
data,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
},
|
},
|
||||||
|
@ -124,7 +124,6 @@ const create2DGraph = (
|
|||||||
container: container as HTMLElement,
|
container: container as HTMLElement,
|
||||||
width,
|
width,
|
||||||
height: 1400,
|
height: 1400,
|
||||||
type: 'graph',
|
|
||||||
renderer: rendererType,
|
renderer: rendererType,
|
||||||
data: dataFor2D,
|
data: dataFor2D,
|
||||||
modes: {
|
modes: {
|
||||||
@ -223,7 +222,6 @@ const create3DGraph = async () => {
|
|||||||
container: container as HTMLDivElement,
|
container: container as HTMLDivElement,
|
||||||
width,
|
width,
|
||||||
height: 1400,
|
height: 1400,
|
||||||
type: 'graph',
|
|
||||||
renderer: 'webgl-3d',
|
renderer: 'webgl-3d',
|
||||||
data: dataFor3D,
|
data: dataFor3D,
|
||||||
// layout: {
|
// layout: {
|
||||||
|
@ -44,7 +44,6 @@ export default () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data,
|
data,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
},
|
},
|
||||||
|
@ -66,7 +66,6 @@ export default () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data,
|
data,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
},
|
},
|
||||||
|
@ -51,7 +51,6 @@ export default () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data,
|
data,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
},
|
},
|
||||||
|
@ -44,7 +44,6 @@ export default () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data,
|
data,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
},
|
},
|
||||||
|
@ -32,6 +32,7 @@ import fisheye from './plugins/fisheye';
|
|||||||
import tooltip from './demo/tooltip';
|
import tooltip from './demo/tooltip';
|
||||||
import comboBasic from './combo/combo-basic';
|
import comboBasic from './combo/combo-basic';
|
||||||
import animations_node_build_in from './animations/node-build-in';
|
import animations_node_build_in from './animations/node-build-in';
|
||||||
|
import treeGraph from './tree/tree-graph';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
behaviors_activateRelations,
|
behaviors_activateRelations,
|
||||||
@ -68,4 +69,5 @@ export {
|
|||||||
tooltip,
|
tooltip,
|
||||||
comboBasic,
|
comboBasic,
|
||||||
animations_node_build_in,
|
animations_node_build_in,
|
||||||
|
treeGraph,
|
||||||
};
|
};
|
||||||
|
@ -231,7 +231,6 @@ export default () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
// supported behavior
|
// supported behavior
|
||||||
|
@ -234,7 +234,6 @@ export default () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
// 支持的 behavior
|
// 支持的 behavior
|
||||||
|
@ -231,7 +231,6 @@ export default () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
// supported behavior
|
// supported behavior
|
||||||
|
@ -227,7 +227,6 @@ export default (context: TestCaseContext) => {
|
|||||||
// 2.create graph
|
// 2.create graph
|
||||||
graph = new Graph({
|
graph = new Graph({
|
||||||
...context,
|
...context,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
// supported behavior
|
// supported behavior
|
||||||
|
@ -6,7 +6,6 @@ export default (context: TestCaseContext) => {
|
|||||||
const { width, height } = context;
|
const { width, height } = context;
|
||||||
return new G6.Graph({
|
return new G6.Graph({
|
||||||
...context,
|
...context,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'd3force',
|
type: 'd3force',
|
||||||
|
@ -17,7 +17,6 @@ export default async () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
renderer: 'webgl-3d',
|
renderer: 'webgl-3d',
|
||||||
modes: {
|
modes: {
|
||||||
|
@ -13,7 +13,6 @@ export default async () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'force-wasm',
|
type: 'force-wasm',
|
||||||
|
@ -17,7 +17,6 @@ export default async () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'forceatlas2-wasm',
|
type: 'forceatlas2-wasm',
|
||||||
|
@ -10,7 +10,6 @@ export default async () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'fruchterman-gpu',
|
type: 'fruchterman-gpu',
|
||||||
|
@ -17,7 +17,6 @@ export default async () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'fruchterman-wasm',
|
type: 'fruchterman-wasm',
|
||||||
|
@ -77,7 +77,6 @@ export default async () => {
|
|||||||
container: $container1,
|
container: $container1,
|
||||||
width: WIDTH,
|
width: WIDTH,
|
||||||
height: HEIGHT,
|
height: HEIGHT,
|
||||||
type: 'graph',
|
|
||||||
renderer: 'webgl-3d',
|
renderer: 'webgl-3d',
|
||||||
modes: {
|
modes: {
|
||||||
default: [
|
default: [
|
||||||
@ -144,7 +143,6 @@ export default async () => {
|
|||||||
container: $container2,
|
container: $container2,
|
||||||
width: WIDTH,
|
width: WIDTH,
|
||||||
height: HEIGHT,
|
height: HEIGHT,
|
||||||
type: 'graph',
|
|
||||||
renderer: 'webgl-3d',
|
renderer: 'webgl-3d',
|
||||||
modes: {
|
modes: {
|
||||||
default: [
|
default: [
|
||||||
|
@ -135,7 +135,6 @@ export default async () => {
|
|||||||
container: $container1,
|
container: $container1,
|
||||||
width: WIDTH,
|
width: WIDTH,
|
||||||
height: HEIGHT,
|
height: HEIGHT,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'force-wasm',
|
type: 'force-wasm',
|
||||||
@ -171,7 +170,6 @@ export default async () => {
|
|||||||
container: $container2,
|
container: $container2,
|
||||||
width: WIDTH,
|
width: WIDTH,
|
||||||
height: HEIGHT,
|
height: HEIGHT,
|
||||||
type: 'graph',
|
|
||||||
data: JSON.parse(JSON.stringify(data)),
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'force',
|
type: 'force',
|
||||||
|
@ -1944,7 +1944,6 @@ const createGraph = async () => {
|
|||||||
container: container as HTMLElement,
|
container: container as HTMLElement,
|
||||||
width,
|
width,
|
||||||
height: 1200,
|
height: 1200,
|
||||||
type: 'graph',
|
|
||||||
// renderer: 'webgl',
|
// renderer: 'webgl',
|
||||||
data: { nodes, edges },
|
data: { nodes, edges },
|
||||||
layout: {
|
layout: {
|
||||||
|
@ -139,7 +139,6 @@ export default async () => {
|
|||||||
container: 'container',
|
container: 'container',
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'force',
|
type: 'force',
|
||||||
rankdir: 'LR',
|
rankdir: 'LR',
|
||||||
|
266
packages/g6/tests/demo/tree/tree-graph.ts
Normal file
266
packages/g6/tests/demo/tree/tree-graph.ts
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
import Stats from 'stats-js';
|
||||||
|
import G6 from '../../../src/index';
|
||||||
|
import { container, height, width } from '../../datasets/const';
|
||||||
|
import { CanvasEvent } from '@antv/g';
|
||||||
|
|
||||||
|
const treeDataCfg = {
|
||||||
|
type: 'treeData',
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
id: 'root',
|
||||||
|
data: {
|
||||||
|
// collapsed: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'c1',
|
||||||
|
data: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'c1-c1',
|
||||||
|
data: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'c2',
|
||||||
|
data: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'root2',
|
||||||
|
data: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 't2c1',
|
||||||
|
data: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 't2c1-c1',
|
||||||
|
data: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 't2c2',
|
||||||
|
data: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const graphDataCfg = {
|
||||||
|
type: 'graphData',
|
||||||
|
value: {
|
||||||
|
nodes: [
|
||||||
|
{ id: 'node1', data: { isRoot: true, collapsed: true } },
|
||||||
|
{ id: 'node2', data: {} },
|
||||||
|
{ id: 'node3', data: {} },
|
||||||
|
{ id: 'node4', data: {} },
|
||||||
|
{ id: 'node5', data: {} },
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
{ id: 'edge1', source: 'node1', target: 'node2', data: {} },
|
||||||
|
{ id: 'edge2', source: 'node1', target: 'node3', data: {} },
|
||||||
|
{ id: 'edge3', source: 'node1', target: 'node4', data: {} },
|
||||||
|
// { id: 'edge4', source: 'node2', target: 'node3', data: {} },
|
||||||
|
// { id: 'edge5', source: 'node3', target: 'node4', data: {} },
|
||||||
|
{ id: 'edge6', source: 'node4', target: 'node5', data: {} },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const dataGenerator = (nodeNum, edgeNum) => {
|
||||||
|
const nodes: any = [];
|
||||||
|
const edges: any = [];
|
||||||
|
for (let i = 0; i < nodeNum; i++) {
|
||||||
|
nodes.push({
|
||||||
|
id: `node-${i}`,
|
||||||
|
data: {
|
||||||
|
x: Math.random() * 1000,
|
||||||
|
y: Math.random() * 1000,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let i = 0; i < edgeNum; i++) {
|
||||||
|
edges.push({
|
||||||
|
id: `edge-${i}`,
|
||||||
|
source: nodes[Math.floor(Math.random() * nodeNum)].id,
|
||||||
|
target: nodes[Math.floor(Math.random() * nodeNum)].id,
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { nodes, edges };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async () => {
|
||||||
|
// const data = dataGenerator(90000, 10000);
|
||||||
|
// console.log('data', data);
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
layout: {
|
||||||
|
type: 'compactBox',
|
||||||
|
// type: 'grid',
|
||||||
|
},
|
||||||
|
node: (innerModel) => {
|
||||||
|
const { x, y, labelShape } = innerModel.data;
|
||||||
|
return {
|
||||||
|
...innerModel,
|
||||||
|
data: {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
animates: {
|
||||||
|
update: [
|
||||||
|
{
|
||||||
|
fields: ['x', 'y'],
|
||||||
|
duration: 500,
|
||||||
|
shapeId: 'group',
|
||||||
|
order: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hide: [
|
||||||
|
{
|
||||||
|
fields: ['opacity'],
|
||||||
|
duration: 200,
|
||||||
|
shapeId: 'keyShape',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fields: ['opacity'],
|
||||||
|
duration: 200,
|
||||||
|
shapeId: 'labelShape',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
show: [
|
||||||
|
{
|
||||||
|
fields: ['opacity'],
|
||||||
|
duration: 1000,
|
||||||
|
shapeId: 'keyShape',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fields: ['opacity'],
|
||||||
|
duration: 1000,
|
||||||
|
shapeId: 'labelShape',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// animate in shapes, unrelated to each other, excuted parallely
|
||||||
|
labelShape: {
|
||||||
|
text: innerModel.id,
|
||||||
|
...labelShape,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
edge: (innerModel) => {
|
||||||
|
return {
|
||||||
|
...innerModel,
|
||||||
|
data: {
|
||||||
|
...innerModel.data,
|
||||||
|
animates: {
|
||||||
|
// hide: [
|
||||||
|
// {
|
||||||
|
// fields: ['opacity'],
|
||||||
|
// duration: 200,
|
||||||
|
// shapeId: 'keyShape',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// fields: ['opacity'],
|
||||||
|
// duration: 200,
|
||||||
|
// shapeId: 'labelShape',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// show: [
|
||||||
|
// {
|
||||||
|
// fields: ['opacity'],
|
||||||
|
// duration: 1000,
|
||||||
|
// shapeId: 'keyShape',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// fields: ['opacity'],
|
||||||
|
// duration: 1000,
|
||||||
|
// shapeId: 'labelShape',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// node: {
|
||||||
|
// animates: {
|
||||||
|
// update: [
|
||||||
|
// {
|
||||||
|
// fields: ['x', 'y'],
|
||||||
|
// duration: 2000,
|
||||||
|
// shapeId: 'group',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// labelShape: {
|
||||||
|
// text: {
|
||||||
|
// fields: ['id'],
|
||||||
|
// formatter: (model) => model.id,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
data: treeDataCfg,
|
||||||
|
// data: graphDataCfg,
|
||||||
|
modes: {
|
||||||
|
default: [
|
||||||
|
'drag-canvas',
|
||||||
|
'zoom-canvas',
|
||||||
|
{
|
||||||
|
type: 'collapse-expand-tree',
|
||||||
|
trigger: 'click',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const stats = new Stats();
|
||||||
|
stats.showPanel(0);
|
||||||
|
document.body.appendChild(stats.dom);
|
||||||
|
|
||||||
|
graph.canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => {
|
||||||
|
if (stats) {
|
||||||
|
stats.update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let collapsed = true;
|
||||||
|
graph.translateTo({ x: 100, y: 100 });
|
||||||
|
|
||||||
|
graph.on('canvas:click', (e) => {
|
||||||
|
/** === change graph data / tree data === */
|
||||||
|
// graph.changeData(treeDataCfg);
|
||||||
|
/** === change layout === */
|
||||||
|
// graph.layout({ type: 'compactBox' });
|
||||||
|
/** === collapse / expand === */
|
||||||
|
const ids = ['root2', 'root']; //['root']; //['node1']; //
|
||||||
|
collapsed ? graph.expand(ids) : graph.collapse(ids);
|
||||||
|
collapsed = !collapsed;
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.on('canvas:contextmenu', (e) => {
|
||||||
|
console.log('contextmenu');
|
||||||
|
/** === updateData === */
|
||||||
|
// graph.updateData('node', {
|
||||||
|
// id: 'node2',
|
||||||
|
// data: { labelShape: { text: 'updated!!' } },
|
||||||
|
// });
|
||||||
|
|
||||||
|
/** === remove a child / subtree root === */
|
||||||
|
// graph.removeData('node', ['node4']);
|
||||||
|
|
||||||
|
/** === add a child === */
|
||||||
|
// graph.addData('node', [{ id: 'newnode', data: {} }]);
|
||||||
|
// graph.addData('edge', [
|
||||||
|
// { id: 'newedge', source: 'node1', target: 'newnode', data: {} },
|
||||||
|
// ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
};
|
@ -10,7 +10,6 @@ const createGraph = () => {
|
|||||||
container: container as HTMLElement,
|
container: container as HTMLElement,
|
||||||
width,
|
width,
|
||||||
height: 1200,
|
height: 1200,
|
||||||
type: 'graph',
|
|
||||||
// renderer: 'webgl',
|
// renderer: 'webgl',
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
|
16
packages/g6/tests/intergration/layouts/circular.ts
Normal file
16
packages/g6/tests/intergration/layouts/circular.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import G6 from '../../../src/index';
|
||||||
|
import { container, data, height, width } from '../../datasets/const';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return new G6.Graph({
|
||||||
|
container,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
data,
|
||||||
|
layout: {
|
||||||
|
type: 'circular',
|
||||||
|
center: [250, 250],
|
||||||
|
radius: 200,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
56
packages/g6/tests/intergration/layouts/force-3d.ts
Normal file
56
packages/g6/tests/intergration/layouts/force-3d.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import G6 from '../../../src/index';
|
||||||
|
import { container, data, height, width } from '../../datasets/const';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return new G6.Graph({
|
||||||
|
container,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
renderer: 'webgl-3d',
|
||||||
|
modes: {
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
type: 'orbit-canvas-3d',
|
||||||
|
trigger: 'drag',
|
||||||
|
},
|
||||||
|
'zoom-canvas-3d',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
data: JSON.parse(JSON.stringify(data)),
|
||||||
|
layout: {
|
||||||
|
type: 'force',
|
||||||
|
dimensions: 3,
|
||||||
|
iterations: 100,
|
||||||
|
center: [width / 2, height / 2, 0],
|
||||||
|
},
|
||||||
|
edge: {
|
||||||
|
type: 'line-edge',
|
||||||
|
keyShape: {
|
||||||
|
lineWidth: 2,
|
||||||
|
stroke: 'grey',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
type: 'sphere-node',
|
||||||
|
keyShape: {
|
||||||
|
opacity: 0.6,
|
||||||
|
},
|
||||||
|
// labelShape: {
|
||||||
|
// text: 'node-label',
|
||||||
|
// },
|
||||||
|
// iconShape: {
|
||||||
|
// img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
nodeState: {
|
||||||
|
selected: {
|
||||||
|
keyShape: {
|
||||||
|
fill: '#f00',
|
||||||
|
},
|
||||||
|
labelShape: {
|
||||||
|
fontSize: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -8,7 +8,6 @@ describe('behavior', () => {
|
|||||||
it('behavior in spec, add / remove / update a behavior in defualt mode', () => {
|
it('behavior in spec, add / remove / update a behavior in defualt mode', () => {
|
||||||
const graph = new G6.Graph({
|
const graph = new G6.Graph({
|
||||||
container,
|
container,
|
||||||
type: 'graph',
|
|
||||||
data: { nodes: [], edges: [] },
|
data: { nodes: [], edges: [] },
|
||||||
modes: {
|
modes: {
|
||||||
default: [
|
default: [
|
||||||
@ -116,7 +115,6 @@ describe('behavior', () => {
|
|||||||
});
|
});
|
||||||
const graph = new CustomGraph({
|
const graph = new CustomGraph({
|
||||||
container,
|
container,
|
||||||
type: 'graph',
|
|
||||||
data: { nodes: [], edges: [] },
|
data: { nodes: [], edges: [] },
|
||||||
modes: {
|
modes: {
|
||||||
default: [
|
default: [
|
||||||
|
@ -9,7 +9,6 @@ describe('brush-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -142,7 +141,6 @@ describe('brush-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -253,7 +251,6 @@ describe('brush-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -368,7 +365,6 @@ describe('brush-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -527,7 +523,6 @@ describe('brush-select behavior with itemTypes', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -660,7 +655,6 @@ describe('brush-select behavior with itemTypes', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -746,7 +740,6 @@ describe('brush-select behavior with itemTypes', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -836,7 +829,6 @@ describe('brush-select behavior with trigger', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -937,7 +929,6 @@ describe('brush-select behavior with trigger', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -1074,7 +1065,6 @@ describe('brush-select behavior with shouldBegin and shouldUpdate', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -1210,7 +1200,6 @@ describe('brush-select behavior with brushStyle', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -105,7 +104,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -172,7 +170,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -232,7 +229,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -283,7 +279,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -355,7 +350,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -426,7 +420,6 @@ describe('drag-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,6 @@ describe('lasso-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -158,7 +157,6 @@ describe('lasso-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -277,7 +275,6 @@ describe('lasso-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -400,7 +397,6 @@ describe('lasso-select behavior with selectSetMode', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -579,7 +575,6 @@ describe('lasso-select behavior with itemTypes', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -724,7 +719,6 @@ describe('lasso-select behavior with itemTypes', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -818,7 +812,6 @@ describe('lasso-select behavior with itemTypes', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -912,7 +905,6 @@ describe('lasso-select behavior with trigger', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -1017,7 +1009,6 @@ describe('lasso-select behavior with trigger', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -1170,7 +1161,6 @@ describe('lasso-select behavior with shouldBegin and shouldUpdate', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -1303,7 +1293,6 @@ describe('lasso-select behavior with brushStyle', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,6 @@ describe('zoom-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -93,7 +92,6 @@ describe('zoom-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -149,7 +147,6 @@ describe('zoom-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
@ -226,7 +223,6 @@ describe('zoom-canvas behavior', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
},
|
},
|
||||||
|
@ -10,7 +10,6 @@ describe('click-select', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200, keyShape: { fill: '#0f0' } } },
|
{ id: 'node1', data: { x: 100, y: 200, keyShape: { fill: '#0f0' } } },
|
||||||
|
@ -24,7 +24,6 @@ describe('data', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data, // with data, graph will be rendered in constructor
|
data, // with data, graph will be rendered in constructor
|
||||||
});
|
});
|
||||||
graph.on('afterrender', () => {
|
graph.on('afterrender', () => {
|
||||||
|
@ -11,7 +11,6 @@ const createGraph = (dragNodeOptions: DragNodeOptions): IGraph => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200, keyShape: { fill: '#0f0' } } },
|
{ id: 'node1', data: { x: 100, y: 200, keyShape: { fill: '#0f0' } } },
|
||||||
|
@ -25,7 +25,6 @@ describe('edge item', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['drag-node'],
|
default: ['drag-node'],
|
||||||
},
|
},
|
||||||
@ -265,7 +264,6 @@ describe('edge mapper', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
};
|
};
|
||||||
it('function mapper', (done) => {
|
it('function mapper', (done) => {
|
||||||
const graph = new G6.Graph({
|
const graph = new G6.Graph({
|
||||||
@ -373,7 +371,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -507,7 +504,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -769,7 +765,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -897,7 +892,6 @@ describe('cubic-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
@ -1137,7 +1131,6 @@ describe('cubic-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: stateData,
|
data: stateData,
|
||||||
modes: {
|
modes: {
|
||||||
// Supported behavior
|
// Supported behavior
|
||||||
@ -1272,7 +1265,6 @@ describe('cubic-horizon-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
@ -1415,7 +1407,6 @@ describe('cubic-horizon-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
@ -1654,7 +1645,6 @@ describe('cubic-horizon-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: stateData,
|
data: stateData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['activate-relations'],
|
default: ['activate-relations'],
|
||||||
@ -1788,7 +1778,6 @@ describe('cubic-vertical-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
@ -2027,7 +2016,6 @@ describe('cubic-vertical-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: stateData,
|
data: stateData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['activate-relations'],
|
default: ['activate-relations'],
|
||||||
@ -2161,7 +2149,6 @@ describe('cubic-vertical-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
type: 'graph',
|
|
||||||
data: defaultData,
|
data: defaultData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
@ -2400,7 +2387,6 @@ describe('cubic-vertical-edge unit test', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: stateData,
|
data: stateData,
|
||||||
modes: {
|
modes: {
|
||||||
default: ['activate-relations'],
|
default: ['activate-relations'],
|
||||||
|
@ -31,7 +31,6 @@ describe('node item', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
renderer: 'webgl-3d',
|
renderer: 'webgl-3d',
|
||||||
// renderer: 'canvas',
|
// renderer: 'canvas',
|
||||||
modes: {
|
modes: {
|
||||||
|
@ -124,7 +124,6 @@ const createGraph = (props) => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: clonedData,
|
data: clonedData,
|
||||||
...props,
|
...props,
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -35,7 +34,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -123,7 +121,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -147,7 +144,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -185,7 +181,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -224,7 +219,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -262,7 +256,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'd3force',
|
type: 'd3force',
|
||||||
@ -289,7 +282,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -342,7 +334,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -388,7 +379,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'd3force',
|
type: 'd3force',
|
||||||
@ -417,7 +407,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'd3force',
|
type: 'd3force',
|
||||||
@ -470,7 +459,6 @@ describe('layout', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'myCustomLayout',
|
type: 'myCustomLayout',
|
||||||
|
@ -26,7 +26,6 @@ describe('node item', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -138,7 +137,6 @@ describe('node mapper', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
};
|
};
|
||||||
it('function mapper', (done) => {
|
it('function mapper', (done) => {
|
||||||
const graph = new G6.Graph({
|
const graph = new G6.Graph({
|
||||||
@ -323,7 +321,6 @@ describe('register node', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -465,7 +462,6 @@ describe('register node', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -533,7 +529,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -677,7 +672,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -920,7 +914,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,6 @@ const createGraph = (plugins) => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200, nodeType: 'a' } },
|
{ id: 'node1', data: { x: 100, y: 200, nodeType: 'a' } },
|
||||||
@ -65,9 +64,9 @@ const createGraph = (plugins) => {
|
|||||||
describe('grid plugin', () => {
|
describe('grid plugin', () => {
|
||||||
test('grid with string config', () => {
|
test('grid with string config', () => {
|
||||||
const graph = createGraph([
|
const graph = createGraph([
|
||||||
{
|
{
|
||||||
img: 'url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImdyaWQiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTSAwIDEwIEwgNDAgMTAgTSAxMCAwIEwgMTAgNDAgTSAwIDIwIEwgNDAgMjAgTSAyMCAwIEwgMjAgNDAgTSAwIDMwIEwgNDAgMzAgTSAzMCAwIEwgMzAgNDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2UwZTBlMCIgb3BhY2l0eT0iMC4yIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNIDQwIDAgTCAwIDAgMCA0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIiBzdHJva2Utd2lkdGg9IjEiLz48L3BhdHRlcm4+PC9kZWZzPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JpZCkiLz48L3N2Zz4=)'
|
img: 'url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImdyaWQiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTSAwIDEwIEwgNDAgMTAgTSAxMCAwIEwgMTAgNDAgTSAwIDIwIEwgNDAgMjAgTSAyMCAwIEwgMjAgNDAgTSAwIDMwIEwgNDAgMzAgTSAzMCAwIEwgMzAgNDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2UwZTBlMCIgb3BhY2l0eT0iMC4yIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNIDQwIDAgTCAwIDAgMCA0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIiBzdHJva2Utd2lkdGg9IjEiLz48L3BhdHRlcm4+PC9kZWZzPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JpZCkiLz48L3N2Zz4=)',
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -10,7 +10,6 @@ const createGraph = (plugins) => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200, nodeType: 'a' } },
|
{ id: 'node1', data: { x: 100, y: 200, nodeType: 'a' } },
|
||||||
|
@ -9,7 +9,6 @@ const createGraph = (plugins) => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200 } },
|
{ id: 'node1', data: { x: 100, y: 200 } },
|
||||||
|
@ -9,7 +9,6 @@ const createGraph = (plugins) => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200 } },
|
{ id: 'node1', data: { x: 100, y: 200 } },
|
||||||
|
@ -9,7 +9,6 @@ const createGraph = (plugins) => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: 'node1', data: { x: 100, y: 200 } },
|
{ id: 'node1', data: { x: 100, y: 200 } },
|
||||||
|
@ -82,7 +82,6 @@ describe('edge item', () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data,
|
data,
|
||||||
type: 'graph',
|
|
||||||
modes: {
|
modes: {
|
||||||
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
default: ['click-select', 'drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
},
|
},
|
||||||
@ -282,7 +281,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -416,7 +414,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -550,7 +547,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -684,7 +680,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
@ -818,7 +813,6 @@ describe('state', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: {
|
data: {
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,6 @@ describe('behavior', () => {
|
|||||||
it('behavior in spec, add / remove / update a behavior in defualt mode', () => {
|
it('behavior in spec, add / remove / update a behavior in defualt mode', () => {
|
||||||
const graph = new G6.Graph({
|
const graph = new G6.Graph({
|
||||||
container,
|
container,
|
||||||
type: 'graph',
|
|
||||||
data: { nodes: [], edges: [] },
|
data: { nodes: [], edges: [] },
|
||||||
modes: {
|
modes: {
|
||||||
default: ['drag-canvas', 'click-select', 'drag-canvas', 'zoom-canvas'],
|
default: ['drag-canvas', 'click-select', 'drag-canvas', 'zoom-canvas'],
|
||||||
|
@ -1887,7 +1887,6 @@ const createGraph = (props) => {
|
|||||||
// renderer: 'webgl',
|
// renderer: 'webgl',
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: clonedData,
|
data: clonedData,
|
||||||
// data: {
|
// data: {
|
||||||
// nodes: [clonedData.nodes[0], clonedData.nodes[10]],
|
// nodes: [clonedData.nodes[0], clonedData.nodes[10]],
|
||||||
|
@ -88,7 +88,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
@ -203,7 +202,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: clone(data),
|
data: clone(data),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
@ -430,7 +428,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data: clone(data),
|
data: clone(data),
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
@ -712,7 +709,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
|
@ -27,7 +27,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
@ -126,7 +125,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
@ -255,7 +253,6 @@ describe('theme', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'grid',
|
type: 'grid',
|
||||||
|
@ -12,7 +12,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -42,7 +41,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -85,7 +83,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -131,7 +128,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -208,7 +204,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -259,7 +254,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -385,7 +379,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -422,7 +415,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -473,7 +465,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
@ -542,7 +533,6 @@ describe('viewport', () => {
|
|||||||
container,
|
container,
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
type: 'graph',
|
|
||||||
data,
|
data,
|
||||||
layout: {
|
layout: {
|
||||||
type: 'circular',
|
type: 'circular',
|
||||||
|
Loading…
Reference in New Issue
Block a user