fix:修复少量bug

This commit is contained in:
Phenom
2021-04-16 15:38:52 +08:00
parent 72fcf5394a
commit 0dcad0f117
18 changed files with 824 additions and 173 deletions
+123
View File
@@ -0,0 +1,123 @@
import { Engine } from "../engine";
import { Util } from "./../Common/util";
export class Behavior {
private engine: Engine;
private graphInstance;
constructor(engine: Engine, graphInstance) {
this.engine = engine;
this.graphInstance = graphInstance;
const interactionOptions = this.engine.interactionOptions;
if(interactionOptions.dragNode) {
this.initDragNode();
}
if(interactionOptions.selectNode) {
this.initSelectNode();
}
}
/**
* 初始化节点拖拽事件
*/
private initDragNode() {
let pointer = null,
pointerX = null,
pointerY = null,
dragStartX = null,
dragStartY = null;
this.graphInstance.on('node:dragstart', ev => {
pointer = this.graphInstance.findById(ev.item.getModel().externalPointerId);
if(pointer) {
pointerX = pointer.getModel().x,
pointerY = pointer.getModel().y;
dragStartX = ev.canvasX;
dragStartY = ev.canvasY;
}
});
this.graphInstance.on('node:dragend', ev => {
pointer = null;
pointerX = null,
pointerY = null,
dragStartX = null,
dragStartY = null;
});
this.graphInstance.on('node:drag', ev => {
if(!pointer) {
return;
}
let dx = ev.canvasX - dragStartX,
dy = ev.canvasY - dragStartY,
zoom = this.graphInstance.getZoom();
pointer.updatePosition({
x: pointerX + dx / zoom,
y: pointerY + dy / zoom
});
});
}
/**
* 初始化节/边选中
*/
private initSelectNode() {
let defaultHighlightColor = '#f08a5d',
curSelectItem = null,
curSelectItemStyle = null;
const selectCallback = ev => {
const item = ev.item,
type = item.getType(),
highlightColor = item.getModel().style.selectedColor;
if(curSelectItem && curSelectItem !== item) {
curSelectItem.update({
style: curSelectItemStyle
});
}
curSelectItem = item;
curSelectItemStyle = Util.objectClone(curSelectItem.getModel().style);
curSelectItem.update({
style: {
...curSelectItemStyle,
[type === 'node'? 'fill': 'stroke']: highlightColor || defaultHighlightColor
}
});
};
this.graphInstance.on('node:click', selectCallback);
this.graphInstance.on('edge:click', selectCallback);
this.graphInstance.on('click', ev => {
if(curSelectItem === null) {
return;
}
curSelectItem.update({
style: curSelectItemStyle
});
curSelectItem = null;
curSelectItemStyle = null;
});
}
/**
* 绑定 G6 事件
* @param eventName
* @param callback
*/
public on(eventName: string, callback: Function) {
if(this.graphInstance) {
this.graphInstance.on(eventName, callback)
}
}
};
+34 -18
View File
@@ -1,7 +1,7 @@
import { Util } from "../Common/util";
import { Engine } from "../engine";
import { ConstructedData } from "../Model/modelConstructor";
import { Element, Pointer } from "../Model/modelData";
import { Element, Model, Pointer } from "../Model/modelData";
import { LayoutOptions, PointerOption } from "../options";
import { Bound, BoundingRect } from "./boundingRect";
@@ -10,31 +10,31 @@ import { Bound, BoundingRect } from "./boundingRect";
export class Layouter {
private engine: Engine;
private containerWidth: number;
private containerHeight: number;
constructor(engine: Engine, containerWidth: number, containerHeight: number) {
constructor(engine: Engine) {
this.engine = engine;
this.containerWidth = containerWidth;
this.containerHeight = containerHeight;
}
/**
* 将视图调整至画布中心
* @param nodes
*/
private fiTCenter(nodes: (Element | Pointer)[]) {
const viewBound: BoundingRect = nodes.map(item => item.getBound()).reduce((prev, cur) => Bound.union(prev, cur));
private fitCenter(models: Model[]) {
const viewBound: BoundingRect = models.map(item => item.getBound()).reduce((prev, cur) => Bound.union(prev, cur));
let centerX = this.containerWidth / 2, centerY = this.containerHeight / 2,
let width = this.engine.getGraphInstance().getWidth(),
height = this.engine.getGraphInstance().getHeight(),
centerX = width / 2, centerY = height / 2,
boundCenterX = viewBound.x + viewBound.width / 2,
boundCenterY = viewBound.y + viewBound.height / 2,
dx = centerX - boundCenterX,
dy = centerY - boundCenterY;
nodes.forEach(item => {
item.set('x', item.get('x') + dx);
item.set('y', item.get('y') + dy)
models.forEach(item => {
item.set({
x: item.get('x') + dx,
y: item.get('y') + dy
});
});
}
@@ -50,8 +50,10 @@ export class Layouter {
pointerList.forEach(item => {
let targetBound: BoundingRect = item.target.getBound();
item.set('x', targetBound.x + targetBound.width / 2);
item.set('y', targetBound.y - offset);
item.set({
x: targetBound.x + targetBound.width / 2,
y: targetBound.y - offset
});
});
});
}
@@ -59,11 +61,21 @@ export class Layouter {
/**
* 主布局函数
* @param constructedData
* @param modelList
* @param layoutFn
*/
public layout(constructedData: ConstructedData, layoutFn: (element: { [ket: string]: Element[] }, layoutOptions: LayoutOptions) => void) {
const options: LayoutOptions = this.engine.layoutOptions,
nodes: (Element | Pointer)[] = [...Util.converterList(constructedData.element), ...Util.converterList(constructedData.pointer)]
public layout(constructedData: ConstructedData, modelList: Model[], layoutFn: (element: { [ket: string]: Element[] }, layoutOptions: LayoutOptions) => void) {
const options: LayoutOptions = this.engine.layoutOptions;
// 首先初始化所有节点的坐标为0,且设定旋转
modelList.forEach(item => {
item.G6Item = item.shadowG6Item;
if(item.type === 'element' || item.type === 'pointer') {
item.set('rotation', item.get('rotation'));
item.set({ x: 0, y: 0 });
}
});
// 布局节点
layoutFn.call(this.engine, constructedData.element, options);
@@ -72,6 +84,10 @@ export class Layouter {
this.layoutPointer(constructedData.pointer);
// 将视图调整到画布中心
options.fitCenter && this.fiTCenter(nodes);
options.fitCenter && this.fitCenter(modelList);
modelList.forEach(item => {
item.G6Item = item.renderG6Item;
});
}
}
+55 -48
View File
@@ -4,6 +4,7 @@ import { ConstructedData } from '../Model/modelConstructor';
import { Util } from '../Common/util';
import { Animations } from './animation';
import { SV } from '../StructV';
import { Model } from './../Model/modelData';
@@ -21,12 +22,14 @@ export class Renderer {
private isFirstRender: boolean;
private prevRenderData: G6Data;
private graphInstance;
private helpGraphInstance;
private shadowGraphInstance;
private modelList: Model[];
constructor(engine: Engine, DOMContainer: HTMLElement, containerWidth: number, containerHeight: number) {
constructor(engine: Engine, DOMContainer: HTMLElement) {
this.engine = engine;
this.DOMContainer = DOMContainer;
this.isFirstRender = true;
this.modelList = [];
this.prevRenderData = {
nodes: [],
edges: []
@@ -34,12 +37,33 @@ export class Renderer {
const enable: boolean = this.engine.animationOptions.enable === undefined? true: this.engine.animationOptions.enable,
duration: number = this.engine.animationOptions.duration,
timingFunction: string = this.engine.animationOptions.timingFunction;
timingFunction: string = this.engine.animationOptions.timingFunction,
interactionOptions = this.engine.interactionOptions;
const modeMap = {
drag: 'drag-canvas',
zoom: 'zoom-canvas',
dragNode: {
type: 'drag-node',
shouldBegin: n => {
// 不允许拖拽外部指针
if (n.item && n.item.getModel().modelType === 'pointer') return false;
return true;
}
}
},
defaultModes = [];
Object.keys(interactionOptions).forEach(item => {
if(interactionOptions[item] === true && modeMap[item] !== undefined) {
defaultModes.push(modeMap[item]);
}
});
this.graphInstance = new SV.G6.Graph({
container: DOMContainer,
width: containerWidth,
height: containerHeight,
width: DOMContainer.offsetWidth,
height: DOMContainer.offsetHeight,
animate: enable,
animateCfg: {
duration: duration,
@@ -47,40 +71,15 @@ export class Renderer {
},
fitView: this.engine.layoutOptions.fitView,
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node']
default: defaultModes
}
});
this.helpGraphInstance = new SV.G6.Graph({
this.shadowGraphInstance = new SV.G6.Graph({
container: DOMContainer.cloneNode()
});
this.animations = new Animations(duration, timingFunction);
this.initBehavior();
}
/**
* 初始化交互
*/
private initBehavior() {
this.graphInstance.on('node:drag', (() => {
let pointer = null;
return ev => {
if(pointer === null) {
pointer = this.graphInstance.findById(ev.item.getModel().externalPointerId);
}
if(pointer) {
pointer.updatePosition({
x: ev.canvasX,
y: ev.canvasY
});
}
console.log(ev);
}
})());
}
/**
@@ -147,21 +146,21 @@ export class Renderer {
let elementList: Element[] = Util.converterList(constructedData.element),
linkList: Link[] = Util.converterList(constructedData.link),
pointerList: Pointer[] = Util.converterList(constructedData.pointer),
nodeList = [...elementList.map(item => item.props), ...pointerList.map(item => item.props)],
edgeList = linkList.map(item => item.props),
list = [...elementList, ...linkList, ...pointerList];
nodeList = [...elementList.map(item => item.cloneProps()), ...pointerList.map(item => item.cloneProps())],
edgeList = linkList.map(item => item.cloneProps());
this.modelList = [...elementList, ...linkList, ...pointerList];
const data: G6Data = {
nodes: <G6NodeModel[]>nodeList,
edges: <G6EdgeModel[]>edgeList
};
this.helpGraphInstance.clear();
this.helpGraphInstance.read(data);
this.shadowGraphInstance.clear();
this.shadowGraphInstance.read(data);
list.forEach(item => {
item.G6Item = this.helpGraphInstance.findById(item.id);
item.afterInitG6Item();
this.modelList.forEach(item => {
item.shadowG6Item = this.shadowGraphInstance.findById(item.id);
});
}
@@ -194,20 +193,28 @@ export class Renderer {
this.handleAppendItems(appendData);
this.handleRemoveItems(removeData);
if(this.engine.layoutOptions.fitView) {
this.graphInstance.fitView();
}
this.modelList.forEach(item => {
item.renderG6Item = this.graphInstance.findById(item.id);
item.G6Item = item.renderG6Item;
});
}
/**
* 绑定 G6 事件
* @param eventName
* @param callback
* 获取 model 队列
*/
public on(eventName: string, callback: Function) {
if(this.graphInstance) {
this.graphInstance.on(eventName, callback)
}
getModelList(): Model[] {
return this.modelList;
}
/**
* 获取 G6 实例
*/
public getGraphInstance() {
return this.graphInstance;
}
}