feat: 添加可以focus节点的函数

This commit is contained in:
黎智洲 2021-09-13 21:35:59 +08:00
parent 3160813119
commit 8347476980
9 changed files with 156 additions and 55 deletions

View File

@ -7,7 +7,7 @@ SV.registerLayouter('BinaryTree', {
default: { default: {
type: 'binary-tree-node', type: 'binary-tree-node',
size: [60, 30], size: [60, 30],
label: '[id]', label: '[data]',
style: { style: {
fill: '#b83b5e', fill: '#b83b5e',
stroke: "#333", stroke: "#333",

View File

@ -18,7 +18,7 @@ SV.registerLayouter('LinkList', {
element: { element: {
default: { default: {
type: 'link-list-node', type: 'link-list-node',
label: '[id]', label: '[data]',
size: [60, 30], size: [60, 30],
style: { style: {
stroke: '#333', stroke: '#333',

View File

@ -79,6 +79,7 @@
<script src="./Layouter/AdjoinTableGraph.js"></script> <script src="./Layouter/AdjoinTableGraph.js"></script>
<script> <script>
const curSelectData = { element: null, style: null };
let cur = SV(document.getElementById('container'), { let cur = SV(document.getElementById('container'), {
freedContainer: document.getElementById('freed'), freedContainer: document.getElementById('freed'),
@ -90,39 +91,58 @@
let data = [{ let data = [{
GeneralizedList: { "LinkList0": {
data: [ "data": [
{ {
"type": "table", "id": "0x617fb0",
"id": 1000, "data": "N",
"next": "table#1001", "next": "0x617ff0",
"tag": 1, "rootExternal": [
"sub": "atom#1002", "before"
root: true,
"external": [
"gl"
]
},
{
"type": "table",
"id": 1001,
"tag": 1,
"external": [
"gl1"
], ],
loopNext: 'table#1000' "type": "default"
}, },
{ {
"type": "atom", "id": "0x617ff0",
"id": 1002, "data": "A",
"tag": 0, "next": "0x618010",
"data": "e", "type": "default"
"external": [
"p4"
]
}, },
{
"id": "0x618010",
"data": "A",
"next": "0x618030",
"type": "default"
},
{
"id": "0x618030",
"data": "B",
"next": "0x618050",
"type": "default"
},
{
"id": "0x618050",
"data": "N",
"next": null,
"type": "default"
}
], ],
layouter: "GeneralizedList" "layouter": "LinkList"
},
"LinkList1": {
"data": [
{
"freed": true,
"id": "0x617fd0",
"data": "",
"next": "0x605010",
"rootExternal": [
"tmpNode"
],
"type": "default"
}
],
"layouter": "LinkList"
} }
}]; }];
@ -142,10 +162,12 @@
document.getElementById('btn-next').addEventListener('click', e => { document.getElementById('btn-next').addEventListener('click', e => {
curData = data[++dataIndex]; curData = data[++dataIndex];
cur.render(curData); cur.render(curData);
// curSelectData.element = null;
// curSelectData.style = null;
}); });
document.getElementById('btn-prev').addEventListener('click', e => { document.getElementById('btn-prev').addEventListener('click', e => {
curData = data[--dataIndex] curData = data[--dataIndex];
cur.render(curData); cur.render(curData);
}); });
@ -164,6 +186,41 @@
}); });
}); });
// -------------------------------------------------------------------------------------------------------
/**
* 选中一个element
*/
function selectElement(element) {
if (element === curSelectData.element) {
return;
}
if (curSelectData.element) {
const style = curSelectData.style;
curSelectData.element.set("style", style);
}
curSelectData.element = element;
curSelectData.style = { ...element.get("style") };
this.setSelectElementStyle(element);
}
/**
* 设置选中的节点的颜色
*/
function setSelectElementStyle(element) {
element.set("style", {
fill: "#e23e57",
});
}
cur.on('node:click', ele => {
selectElement(ele);
});
</script> </script>
</body> </body>

2
dist/sv.js vendored

File diff suppressed because one or more lines are too long

View File

@ -44,6 +44,8 @@ export class Model {
id: string; id: string;
type: string; type: string;
isLeak: boolean; isLeak: boolean;
isDestroy: boolean;
modelType: string;
props: G6NodeModel | G6EdgeModel; props: G6NodeModel | G6EdgeModel;
shadowG6Item; shadowG6Item;
@ -58,6 +60,7 @@ export class Model {
this.G6Item = null; this.G6Item = null;
this.props = <G6NodeModel | G6EdgeModel>{ }; this.props = <G6NodeModel | G6EdgeModel>{ };
this.isLeak = false; this.isLeak = false;
this.isDestroy = false;
} }
/** /**
@ -100,6 +103,10 @@ export class Model {
* @returns * @returns
*/ */
set(attr: string | object, value?: any) { set(attr: string | object, value?: any) {
if(this.isDestroy) {
return;
}
if(typeof attr === 'object') { if(typeof attr === 'object') {
Object.keys(attr).map(item => { Object.keys(attr).map(item => {
this.set(item, attr[item]); this.set(item, attr[item]);
@ -158,6 +165,10 @@ export class Model {
return this.type; return this.type;
} }
getModelType(): string {
return this.modelType;
}
getId(): string { getId(): string {
return this.id; return this.id;
} }
@ -178,6 +189,7 @@ export class Element extends Model {
constructor(id: string, type: string, group: string, layouter: string, sourceElement: SourceElement) { constructor(id: string, type: string, group: string, layouter: string, sourceElement: SourceElement) {
super(id, type); super(id, type);
this.modelType = 'element';
if(type === null) { if(type === null) {
return; return;
@ -219,6 +231,10 @@ export class Element extends Model {
SVModelName: this.type SVModelName: this.type
}; };
} }
getSourceId(): string {
return this.sourceId;
}
}; };
@ -230,6 +246,8 @@ export class Link extends Model {
constructor(id: string, type: string, element: Element, target: Element, index: number) { constructor(id: string, type: string, element: Element, target: Element, index: number) {
super(id, type); super(id, type);
this.modelType = 'link';
this.element = element; this.element = element;
this.target = target; this.target = target;
this.index = index; this.index = index;
@ -277,6 +295,8 @@ export class Marker extends Model {
constructor(id: string, type: string, label: string | string[], target: Element) { constructor(id: string, type: string, label: string | string[], target: Element) {
super(id, type); super(id, type);
this.modelType = 'marker';
this.target = target; this.target = target;
this.label = label; this.label = label;

View File

@ -106,13 +106,15 @@ import { Container } from "./container";
protected afterInitRenderer() { protected afterInitRenderer() {
let g6Instance = this.getG6Instance(), let g6Instance = this.getG6Instance(),
marker = null, marker = null,
markerX = null, markerX = 0,
markerY = null, markerY = 0,
dragStartX = null, dragStartX = 0,
dragStartY = null; dragStartY = 0,
element = null;
g6Instance.on('node:dragstart', ev => { g6Instance.on('node:dragstart', ev => {
const model = ev.item.getModel(); const model = ev.item.getModel();
element = ev.item.SVModel;
if(model.SVModelType === 'marker') { if(model.SVModelType === 'marker') {
return; return;
@ -128,22 +130,33 @@ import { Container } from "./container";
return; return;
} }
dragStartX = ev.canvasX;
dragStartY = ev.canvasY;
marker = g6Instance.findById(model.markerId); marker = g6Instance.findById(model.markerId);
if(marker) { if(marker) {
markerX = marker.getModel().x, markerX = marker.getModel().x,
markerY = marker.getModel().y; markerY = marker.getModel().y;
dragStartX = ev.canvasX;
dragStartY = ev.canvasY;
} }
}); });
g6Instance.on('node:dragend', ev => { g6Instance.on('node:dragend', ev => {
let distanceX = ev.canvasX - dragStartX,
distanceY = ev.canvasY - dragStartY,
elementX = element.get('x'),
elementY = element.get('y');
element.set({
x: elementX + distanceX,
y: elementY + distanceY
});
marker = null; marker = null;
markerX = null, markerX = 0,
markerY = null, markerY = 0,
dragStartX = null, dragStartX = 0,
dragStartY = null; dragStartY = 0;
element = null;
}); });
g6Instance.on('node:drag', ev => { g6Instance.on('node:drag', ev => {

View File

@ -21,6 +21,7 @@ export class Renderer {
private DOMContainer: HTMLElement; // 主可视化视图容器 private DOMContainer: HTMLElement; // 主可视化视图容器
private g6Instance; // g6 实例 private g6Instance; // g6 实例
private prevRenderModelList: Model[] = null;
private isFirstRender: boolean; // 是否为第一次渲染 private isFirstRender: boolean; // 是否为第一次渲染
constructor(engine: Engine, DOMContainer: HTMLElement, g6Options: { [key: string]: any }) { constructor(engine: Engine, DOMContainer: HTMLElement, g6Options: { [key: string]: any }) {
@ -72,12 +73,8 @@ export class Renderer {
* @param modelList * @param modelList
*/ */
public render(modelList: Model[], removeModels: Model[]) { public render(modelList: Model[], removeModels: Model[]) {
let data: G6Data = Util.convertModelList2G6Data(modelList), const renderModelList = [...modelList, ...removeModels],
removeData: G6Data = Util.convertModelList2G6Data(removeModels), renderData: G6Data = Util.convertModelList2G6Data(renderModelList);
renderData: G6Data = {
nodes: [...data.nodes, ...removeData.nodes],
edges: [...data.edges, ...removeData.edges]
};
if(this.isFirstRender) { if(this.isFirstRender) {
this.g6Instance.read(renderData); this.g6Instance.read(renderData);
@ -99,6 +96,13 @@ export class Renderer {
} }
}); });
// 将上一次的model全部标记为已销毁
if(this.prevRenderModelList) {
this.prevRenderModelList.forEach(item => { item.isDestroy = true; });
}
this.prevRenderModelList = renderModelList;
// 把所有连线置顶 // 把所有连线置顶
if(this.isFirstRender) { if(this.isFirstRender) {
this.g6Instance.getEdges().forEach(item => item.toFront()); this.g6Instance.getEdges().forEach(item => item.toFront());

View File

@ -124,7 +124,15 @@ export class ViewManager {
this.handleFreedLabel(freedElements, prevLayoutGroupTable.get(freedGroupName)); this.handleFreedLabel(freedElements, prevLayoutGroupTable.get(freedGroupName));
this.prevFreedElements = freedElements; this.prevFreedElements = freedElements;
return [...freedElements, ...freedMarkers]; const freedItems = [...freedElements, ...freedMarkers];
freedItems.forEach(item => {
item.set('style', {
fill: '#ccc'
});
});
return freedItems;
} }
/** /**

View File

@ -200,18 +200,15 @@ export class Engine {
} }
/** /**
* 使id选中某个节点 * 使id查找某个节点
* @param id * @param id
* @param callback
*/ */
public selectElement(id: string, callback?: (element: Element) => void) { public findElement(id: string) {
const elements = this.getElements(); const elements = this.getElements();
const stringId = id.toString(); const stringId = id.toString();
const targetElement = elements.find(item => item.sourceId === stringId); const targetElement = elements.find(item => item.sourceId === stringId);
if(targetElement) { return targetElement;
callback && callback(targetElement);
}
} }
/** /**
@ -239,7 +236,9 @@ export class Engine {
return; return;
} }
this.viewManager.getG6Instance().on(eventName, callback); this.viewManager.getG6Instance().on(eventName, event => {
callback(event.item.SVModel);
});
} }
/** /**