feat: 增加框选功能
This commit is contained in:
parent
3626a6eb19
commit
3d0f613811
@ -34,7 +34,7 @@ SV.registerLayout('ChainHashTable', {
|
||||
start: {
|
||||
type: 'line',
|
||||
sourceAnchor: 1,
|
||||
targetAnchor: 5,
|
||||
targetAnchor: 6,
|
||||
style: {
|
||||
stroke: '#333',
|
||||
endArrow: {
|
||||
@ -77,7 +77,7 @@ SV.registerLayout('ChainHashTable', {
|
||||
xInterval: 50,
|
||||
yInterval: 50
|
||||
},
|
||||
interaction: {
|
||||
behavior: {
|
||||
dragNode: ['node']
|
||||
}
|
||||
};
|
||||
|
||||
@ -77,6 +77,9 @@ SV.registerLayout('LinkList', {
|
||||
layout: {
|
||||
xInterval: 50,
|
||||
yInterval: 50
|
||||
},
|
||||
behavior: {
|
||||
dragNode: false
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
<button id="resize">resize</button>
|
||||
<button id="relayout">relayout</button>
|
||||
<button id="switch-mode">switch mode</button>
|
||||
<button id="brush-select">brush-select</button>
|
||||
<span id="pos"></span>
|
||||
|
||||
<script src="./../dist/sv.js"></script>
|
||||
@ -89,8 +90,6 @@
|
||||
|
||||
<script>
|
||||
|
||||
const curSelectData = { element: null, style: null };
|
||||
|
||||
let cur = SV(document.getElementById('container'), {
|
||||
view: {
|
||||
leakAreaHeight: 130,
|
||||
@ -101,18 +100,82 @@
|
||||
|
||||
let data = [{
|
||||
Array: {
|
||||
data: [{ id: 1, data: 1, external: 'list' }, { id: 2, data: 2 }, { id: 3, data: 3 }],
|
||||
layouter: 'Array'
|
||||
data: [
|
||||
{ id: 1, data: 1, child: [2, 3], external: 'exx' },
|
||||
{ id: 2, data: 2 },
|
||||
{ id: 3, data: 3, child: [6, 4] },
|
||||
{ id: 4, data: 4 },
|
||||
{ id: 6, data: 6 }
|
||||
],
|
||||
layouter: 'BinaryTree'
|
||||
},
|
||||
L: {
|
||||
data: [
|
||||
{ id: 11, data: 11, next: 22, external: 'tt' },
|
||||
{ id: 22, data: 22, next: 33 },
|
||||
{ id: 33, data: 33, next: 44 },
|
||||
{ id: 44, data: 44, freed: true }
|
||||
],
|
||||
layouter: 'LinkList'
|
||||
},
|
||||
"ChainHashTable": {
|
||||
"data": [
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x618090",
|
||||
"data": "T"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x618030",
|
||||
"data": "N"
|
||||
},
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x6180f0",
|
||||
"data": "U",
|
||||
"start": "node#0x618030"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x617ff0",
|
||||
"data": "V",
|
||||
"next": "node#0x617fd0"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x617fd0",
|
||||
"data": "A"
|
||||
},
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x618010",
|
||||
"data": "O",
|
||||
"start": "node#0x617ff0"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x618050",
|
||||
"data": "K"
|
||||
},
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x6180b0",
|
||||
"data": "R",
|
||||
"start": "node#0x618050"
|
||||
}
|
||||
],
|
||||
"layouter": "ChainHashTable"
|
||||
}
|
||||
}, {
|
||||
Array: {
|
||||
data: [{ id: 1, data: 1 }, { id: 2, data: 2 }],
|
||||
layouter: 'Array'
|
||||
}
|
||||
}, {
|
||||
Array: {
|
||||
data: [{ id: 1, data: 1 }, { id: 5, data: 5 }],
|
||||
layouter: 'Array'
|
||||
data: [
|
||||
{ id: 1, data: 1, child: [2, 3], external: 'exx' },
|
||||
{ id: 2, data: 2 },
|
||||
{ id: 3, data: 3, child: [6, 7] },
|
||||
{ id: 7, data: 7 }
|
||||
],
|
||||
layouter: 'BinaryTree'
|
||||
}
|
||||
}];
|
||||
|
||||
@ -123,6 +186,13 @@
|
||||
let dataIndex = 0,
|
||||
curData = data[dataIndex];
|
||||
|
||||
let enableBrushSelect = false;
|
||||
|
||||
const container = document.getElementById('container'),
|
||||
pos = document.getElementById('pos');
|
||||
|
||||
const leak = document.getElementById('leak');
|
||||
|
||||
cur.render(curData);
|
||||
|
||||
document.getElementById('btn-next').addEventListener('click', e => {
|
||||
@ -135,14 +205,6 @@
|
||||
cur.render(curData);
|
||||
});
|
||||
|
||||
const container = document.getElementById('container'),
|
||||
pos = document.getElementById('pos');
|
||||
|
||||
container.addEventListener('mousemove', e => {
|
||||
let x = e.offsetX, y = e.offsetY;
|
||||
pos.innerHTML = `${x},${y}`;
|
||||
});
|
||||
|
||||
document.getElementById('resize').addEventListener('click', e => {
|
||||
container.style.height = 800 + 'px';
|
||||
cur.resize(container.offsetWidth, container.offsetHeight);
|
||||
@ -156,7 +218,10 @@
|
||||
cur.updateStyle('Array', newArrayOption);
|
||||
});
|
||||
|
||||
const leak = document.getElementById('leak');
|
||||
document.getElementById('brush-select').addEventListener('click', e => {
|
||||
enableBrushSelect = !enableBrushSelect;
|
||||
cur.switchBrushSelect(enableBrushSelect);
|
||||
});
|
||||
|
||||
cur.on('onLeakAreaUpdate', payload => {
|
||||
leak.style.opacity = payload.hasLeak ? 1 : 0;
|
||||
@ -165,6 +230,12 @@
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
|
||||
container.addEventListener('mousemove', e => {
|
||||
let x = e.offsetX, y = e.offsetY;
|
||||
pos.innerHTML = `${x},${y}`;
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
14147
dist/sv.js
vendored
14147
dist/sv.js
vendored
File diff suppressed because one or more lines are too long
199
src/BehaviorHelper/behaviorIssueHelper.ts
Normal file
199
src/BehaviorHelper/behaviorIssueHelper.ts
Normal file
@ -0,0 +1,199 @@
|
||||
import { Graph, INode } from "@antv/g6";
|
||||
import { EventBus } from "../Common/eventBus";
|
||||
import { LayoutGroupTable } from "../Model/modelConstructor";
|
||||
import { SVModel } from "../Model/SVModel";
|
||||
import { SVNode } from "../Model/SVNode";
|
||||
import { ViewContainer } from "../View/viewContainer";
|
||||
|
||||
|
||||
/**
|
||||
* 判断当前节点是否可以单独拖拽
|
||||
* @param node
|
||||
* @param dragNodeOption
|
||||
*/
|
||||
const checkNodeDragAlone = function (node: SVNode, dragNodeOption: boolean | string[]): boolean {
|
||||
const nodeSourceType = node.sourceType;
|
||||
|
||||
if (Array.isArray(dragNodeOption)) {
|
||||
return dragNodeOption.includes(nodeSourceType);
|
||||
}
|
||||
|
||||
if (dragNodeOption === undefined || dragNodeOption === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判定该节点是否可以被拖拽
|
||||
* 1. 当 dragNodeOption 为 true 或者 undefined时,所有节点都可单独拖拽
|
||||
* 2. 当 dragNodeOption 声明了某些节点的type时(字符数组),这些节点可以单独拖拽
|
||||
* 3. 当 dragNodeOption 为 false 或者不包含在声明的type的节点,只能批量拖拽
|
||||
*/
|
||||
export const DetermineNodeDrag = function (layoutGroupTable: LayoutGroupTable, node: SVNode, brushSelectedModels: SVModel[]) {
|
||||
const layoutGroup = layoutGroupTable.get(node.group),
|
||||
dragNodeOption = layoutGroup.options.behavior?.dragNode,
|
||||
canNodeDragAlone = checkNodeDragAlone(node, dragNodeOption);
|
||||
|
||||
if (canNodeDragAlone) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const nodeSourceType = node.sourceType,
|
||||
nodeModelType = node.getModelType(),
|
||||
modelList = (<SVModel[]>layoutGroup[nodeModelType]).filter(item => item.sourceType === nodeSourceType),
|
||||
brushSelectedSameTypeModels = brushSelectedModels.filter(item => {
|
||||
return item.group === node.group &&
|
||||
item.getModelType() === nodeModelType &&
|
||||
item.sourceType === nodeSourceType
|
||||
});
|
||||
|
||||
return modelList.length === brushSelectedSameTypeModels.length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在初始化渲染器之后,修正节点拖拽时,外部指针或者其他 appendage 没有跟着动的问题
|
||||
*
|
||||
*/
|
||||
export function SolveNodeAppendagesDrag(viewContainer: ViewContainer) {
|
||||
const g6Instance: Graph = viewContainer.getG6Instance();
|
||||
|
||||
g6Instance.on('node:dragstart', event => {
|
||||
let node: SVNode = event.item['SVModel'];
|
||||
|
||||
if (node instanceof SVNode === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isNodeSelected = viewContainer.brushSelectedModels.find(item => item.id === node.id);
|
||||
|
||||
// 如果在框选完成之后,拖拽了被框选之外的其他节点,那么取消已框选的节点的选中状态
|
||||
if (isNodeSelected === undefined) {
|
||||
viewContainer.brushSelectedModels.forEach(item => {
|
||||
item.setSelectedState(false);
|
||||
|
||||
if (item instanceof SVNode) {
|
||||
item.appendages.forEach(appendage => appendage.setSelectedState(false));
|
||||
}
|
||||
});
|
||||
viewContainer.brushSelectedModels.length = 0;
|
||||
}
|
||||
});
|
||||
|
||||
g6Instance.on('node:dragend', event => {
|
||||
let node: SVNode = event.item['SVModel'];
|
||||
|
||||
if (node instanceof SVNode === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isNodeSelected = viewContainer.brushSelectedModels.find(item => item.id === node.id);
|
||||
|
||||
// 如果当前拖拽的节点是在已框选选中的节点之中,那么不需要取消选中的状态,否则需要取消
|
||||
if (isNodeSelected === undefined) {
|
||||
node.setSelectedState(false);
|
||||
node.set({
|
||||
x: node.G6Item.getModel().x,
|
||||
y: node.G6Item.getModel().y
|
||||
});
|
||||
|
||||
node.appendages.forEach(item => {
|
||||
item.setSelectedState(false);
|
||||
});
|
||||
}
|
||||
|
||||
viewContainer.brushSelectedModels.forEach(item => {
|
||||
item.set({
|
||||
x: item.G6Item.getModel().x,
|
||||
y: item.G6Item.getModel().y
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检测框选到的节点是不是都可以被选中
|
||||
* @param viewContainer
|
||||
*/
|
||||
export function SolveBrushSelectDrag(viewContainer: ViewContainer) {
|
||||
const g6Instance: Graph = viewContainer.getG6Instance();
|
||||
|
||||
// 当框选完成后,监听被框选节点的数量变化事件,将被框选的节点添加到 brushSelectedModels 数组里面
|
||||
g6Instance.on('nodeselectchange', event => {
|
||||
const selectedItems = event.selectedItems as { nodes: INode[]; },
|
||||
tmpSelectedModelList = [];
|
||||
|
||||
// 如果是点击选中,不理会
|
||||
if (event.target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先清空上一次框选保存的内容
|
||||
viewContainer.brushSelectedModels.length = 0;
|
||||
|
||||
// 首先将已框选中的节点加到一个临时队列
|
||||
selectedItems.nodes.forEach(item => {
|
||||
tmpSelectedModelList.push(item['SVModel']);
|
||||
});
|
||||
|
||||
// 之后逐个检测被框选中的节点是否可以拖拽,可以拖拽的才加入到真正的框选队列
|
||||
selectedItems.nodes.forEach(item => {
|
||||
const node: SVNode = item['SVModel'];
|
||||
|
||||
if (DetermineNodeDrag(viewContainer.getLayoutGroupTable(), node, tmpSelectedModelList)) {
|
||||
viewContainer.brushSelectedModels.push(node);
|
||||
}
|
||||
else {
|
||||
node.setSelectedState(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 解决泄漏区随着视图拖动的问题
|
||||
* @param g6Instance
|
||||
* @param hasLeak
|
||||
*/
|
||||
export function SolveDragCanvasWithLeak(viewContainer: ViewContainer) {
|
||||
let g6Instance = viewContainer.getG6Instance(),
|
||||
prevDy = 0;
|
||||
|
||||
g6Instance.on('viewportchange', event => {
|
||||
if (event.action !== 'translate') {
|
||||
return false;
|
||||
}
|
||||
|
||||
let translateX = event.matrix[7],
|
||||
dy = translateX - prevDy;
|
||||
|
||||
prevDy = translateX;
|
||||
|
||||
viewContainer.leakAreaY = viewContainer.leakAreaY + dy;
|
||||
if (viewContainer.hasLeak) {
|
||||
EventBus.emit('onLeakAreaUpdate', {
|
||||
leakAreaY: viewContainer.leakAreaY,
|
||||
hasLeak: viewContainer.hasLeak
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 解决泄漏区随着视图缩放的问题(这里搞不出来,尽力了)
|
||||
* @param g6Instance
|
||||
* @param generalModelsGroup
|
||||
*/
|
||||
export function SolveZoomCanvasWithLeak(viewContainer: ViewContainer) {
|
||||
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
import { EventBus } from "../Common/eventBus";
|
||||
import { ViewContainer } from "../View/viewContainer";
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param g6Instance
|
||||
* @param hasLeak
|
||||
*/
|
||||
export function InitDragCanvasWithLeak(viewContainer: ViewContainer) {
|
||||
let g6Instance = viewContainer.getG6Instance(),
|
||||
prevDy = 0;
|
||||
|
||||
g6Instance.on('viewportchange', event => {
|
||||
if(event.action !== 'translate') {
|
||||
return false;
|
||||
}
|
||||
|
||||
let translateX = event.matrix[7],
|
||||
dy = translateX- prevDy;
|
||||
|
||||
prevDy = translateX;
|
||||
|
||||
viewContainer.leakAreaY = viewContainer.leakAreaY + dy;
|
||||
if (viewContainer.hasLeak) {
|
||||
EventBus.emit('onLeakAreaUpdate', {
|
||||
leakAreaY: viewContainer.leakAreaY,
|
||||
hasLeak: viewContainer.hasLeak
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
import { Graph } from "@antv/g6";
|
||||
import { SVNode } from "../Model/SVNode";
|
||||
import { SVNodeAppendage } from "../Model/SVNodeAppendage";
|
||||
|
||||
|
||||
/**
|
||||
* 在初始化渲染器之后,修正节点拖拽时,外部指针或者其他 appendage 没有跟着动的问题
|
||||
*
|
||||
*/
|
||||
export function FixNodeMarkerDrag(g6Instance: Graph) {
|
||||
let dragActive: boolean = false,
|
||||
nodeData: { node: SVNode, startX: number, startY: number },
|
||||
appendagesData: { appendage: SVNodeAppendage, startX: number, startY: number }[] = [];
|
||||
|
||||
g6Instance.on('node:dragstart', event => {
|
||||
let node: SVNode = event.item['SVModel'];
|
||||
|
||||
if (node.isNode() === false || node.leaked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dragActive = true;
|
||||
nodeData = {
|
||||
node,
|
||||
startX: event.canvasX,
|
||||
startY: event.canvasY
|
||||
};
|
||||
|
||||
node.appendages.forEach(item => {
|
||||
appendagesData.push({
|
||||
appendage: item,
|
||||
startX: item.get('x'),
|
||||
startY: item.get('y')
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
g6Instance.on('node:dragend', event => {
|
||||
if(!dragActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let node: SVNode = nodeData.node;
|
||||
|
||||
node.set({
|
||||
x: node.G6Item.getModel().x,
|
||||
y: node.G6Item.getModel().y
|
||||
});
|
||||
|
||||
nodeData = null;
|
||||
appendagesData.length = 0;
|
||||
dragActive = false;
|
||||
});
|
||||
|
||||
g6Instance.on('node:drag', ev => {
|
||||
if (!dragActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let dx = ev.canvasX - nodeData.startX,
|
||||
dy = ev.canvasY - nodeData.startY,
|
||||
zoom = g6Instance.getZoom();
|
||||
|
||||
appendagesData.forEach(item => {
|
||||
item.appendage.set({
|
||||
x: item.startX + dx / zoom,
|
||||
y: item.startY + dy / zoom
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
113
src/BehaviorHelper/initG6Behaviors.ts
Normal file
113
src/BehaviorHelper/initG6Behaviors.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { Graph, INode, Modes } from "@antv/g6";
|
||||
import { Engine } from "../engine";
|
||||
import { SVModel } from "../Model/SVModel";
|
||||
import { SVNode } from "../Model/SVNode";
|
||||
import { ViewContainer } from "../View/viewContainer";
|
||||
import { DetermineNodeDrag } from "./behaviorIssueHelper";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 初始化g6 交互options
|
||||
* @param optionsTable
|
||||
* @returns
|
||||
*/
|
||||
export function InitG6Behaviors(engine: Engine, viewContainer: ViewContainer): Modes {
|
||||
|
||||
const dragNodeFilter = event => {
|
||||
let g6Item = event.item,
|
||||
node: SVNode = g6Item.SVModel;
|
||||
|
||||
if (g6Item === null || node.isNode() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const enableDrag = DetermineNodeDrag(viewContainer.getLayoutGroupTable(), node, viewContainer.brushSelectedModels);
|
||||
|
||||
if(enableDrag === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 在拖拽某个节点前,先处理一下上次点击选中的节点,不然会上次选中的节点会跟着一起拖,产生bug
|
||||
if(viewContainer.clickSelectNode) {
|
||||
const isPrevSelectInBrush = viewContainer.brushSelectedModels.find(item => item.id === viewContainer.clickSelectNode.id);
|
||||
|
||||
if(isPrevSelectInBrush === undefined) {
|
||||
viewContainer.clickSelectNode.setSelectedState(false);
|
||||
viewContainer.clickSelectNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 这里之所以要把节点和其 appendages 的选中状态设置为true,是因为 g6 处理拖拽节点的逻辑是将所以已选中的元素一起拖动,
|
||||
// 这样 appendages 就可以很自然地跟着节点动(我是看源码才知道的)
|
||||
node.setSelectedState(true);
|
||||
node.appendages.forEach(item => {
|
||||
item.setSelectedState(true);
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const selectNodeFilter = event => {
|
||||
let g6Item = event.item,
|
||||
node: SVNode = g6Item.SVModel;
|
||||
|
||||
if (g6Item === null || node.isNode() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
viewContainer.clickSelectNode = node;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const brushSelectNodeFilter = G6Item => {
|
||||
const model: SVModel = G6Item.SVModel;
|
||||
|
||||
// 泄漏的元素不能被框选
|
||||
if (model.leaked || model.isNode() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
model.setSelectedState(true);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
const dragNode = {
|
||||
type: 'drag-node',
|
||||
shouldBegin: dragNodeFilter
|
||||
};
|
||||
|
||||
const dragCanvas = {
|
||||
type: 'drag-canvas'
|
||||
};
|
||||
|
||||
const zoomCanvas = {
|
||||
type: 'zoom-canvas'
|
||||
};
|
||||
|
||||
const clickSelect = {
|
||||
type: 'click-select',
|
||||
multiple: false,
|
||||
shouldBegin: selectNodeFilter
|
||||
};
|
||||
|
||||
const brushSelect = {
|
||||
type: 'brush-select',
|
||||
trigger: 'drag',
|
||||
includeEdges: false,
|
||||
shouldUpdate: brushSelectNodeFilter
|
||||
}
|
||||
|
||||
return {
|
||||
default: [dragNode, dragCanvas, clickSelect],
|
||||
brush: [brushSelect, dragNode]
|
||||
};
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
import { SVModel } from "../Model/SVModel";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 初始化g6 交互options
|
||||
* @param optionsTable
|
||||
* @returns
|
||||
*/
|
||||
export function InitViewBehaviors() {
|
||||
const defaultModes = [];
|
||||
|
||||
const dragNodeFilter = event => {
|
||||
let g6Item = event.item,
|
||||
node: SVModel = g6Item.SVModel;
|
||||
|
||||
if (g6Item === null || node.isNode() === false || node.leaked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const selectNodeFilter = event => {
|
||||
let g6Item = event.item,
|
||||
node: SVModel = g6Item.SVModel;
|
||||
|
||||
if (g6Item === null || node.isNode() === false || node.leaked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
defaultModes.push({
|
||||
type: 'drag-node',
|
||||
shouldBegin: dragNodeFilter
|
||||
});
|
||||
|
||||
defaultModes.push({
|
||||
type: 'drag-canvas'
|
||||
});
|
||||
|
||||
// defaultModes.push({
|
||||
// type: 'zoom-canvas'
|
||||
// });
|
||||
|
||||
defaultModes.push({
|
||||
type: 'click-select',
|
||||
shouldBegin: selectNodeFilter
|
||||
});
|
||||
|
||||
return defaultModes;
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
import { EventBus } from "../Common/eventBus";
|
||||
import { ViewContainer } from "../View/viewContainer";
|
||||
|
||||
|
||||
/**
|
||||
* 缩放这里搞不出来,尽力了
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param g6Instance
|
||||
* @param generalModelsGroup
|
||||
*/
|
||||
export function InitZoomCanvasWithLeak(viewContainer: ViewContainer) {
|
||||
let g6Instance = viewContainer.getG6Instance(),
|
||||
prevDy = 0;
|
||||
|
||||
let prevZoom = 1;
|
||||
|
||||
// g6Instance.on('viewportchange', event => {
|
||||
// if(event.action !== 'zoom') {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// console.log(event.matrix);
|
||||
|
||||
// viewContainer.leakAreaY = event.matrix[4] * viewContainer.leakAreaY + event.matrix[7];
|
||||
// if (viewContainer.hasLeak) {
|
||||
// EventBus.emit('onLeakAreaUpdate', {
|
||||
// leakAreaY: viewContainer.leakAreaY,
|
||||
// hasLeak: viewContainer.hasLeak
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
g6Instance.on('wheelzoom', event => {
|
||||
let dy = event.y - viewContainer.leakAreaY,
|
||||
dZoom = prevZoom - g6Instance.getZoom();
|
||||
|
||||
prevZoom = g6Instance.getZoom();
|
||||
|
||||
viewContainer.leakAreaY = viewContainer.leakAreaY + dy * dZoom;
|
||||
if (viewContainer.hasLeak) {
|
||||
EventBus.emit('onLeakAreaUpdate', {
|
||||
leakAreaY: viewContainer.leakAreaY,
|
||||
hasLeak: viewContainer.hasLeak
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { EdgeConfig, GraphData, NodeConfig } from "@antv/g6-core";
|
||||
import { EdgeConfig, GraphData, NodeConfig, registerNode } from "@antv/g6-core";
|
||||
import { LayoutGroup, LayoutGroupTable } from "../Model/modelConstructor";
|
||||
import { SVLink } from "../Model/SVLink";
|
||||
import { SVModel } from "../Model/SVModel";
|
||||
@ -14,10 +14,10 @@ export const Util = {
|
||||
* 生成唯一id
|
||||
*/
|
||||
generateId(): string {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -25,7 +25,7 @@ export const Util = {
|
||||
* @param obj
|
||||
*/
|
||||
objectClone<T extends Object>(obj: T): T {
|
||||
return obj? JSON.parse(JSON.stringify(obj)): null;
|
||||
return obj ? JSON.parse(JSON.stringify(obj)) : null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -36,8 +36,8 @@ export const Util = {
|
||||
removeFromList<T>(list: T[], fn: (item: T) => boolean): T[] {
|
||||
const res: T[] = [];
|
||||
|
||||
for(let i = 0; i < list.length; i++) {
|
||||
if(fn(list[i])) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (fn(list[i])) {
|
||||
let removeItem = list.splice(i, 1);
|
||||
res.push(...removeItem);
|
||||
i--;
|
||||
@ -53,7 +53,7 @@ export const Util = {
|
||||
* @param errorText
|
||||
*/
|
||||
assert(condition: boolean, errorText: string): void | never {
|
||||
if(condition) {
|
||||
if (condition) {
|
||||
throw errorText;
|
||||
}
|
||||
},
|
||||
@ -65,7 +65,7 @@ export const Util = {
|
||||
textParser(text: string): string[] | string {
|
||||
let fieldReg = /\[[^\]]*\]/g;
|
||||
|
||||
if(fieldReg.test(text)) {
|
||||
if (fieldReg.test(text)) {
|
||||
let contents = text.match(fieldReg),
|
||||
values = contents.map(item => item.replace(/\[|\]/g, ''));
|
||||
return values;
|
||||
@ -80,9 +80,9 @@ export const Util = {
|
||||
* @param value
|
||||
*/
|
||||
clamp(value: number, max: number, min: number): number {
|
||||
if(value <= max && value >= min) return value;
|
||||
if(value > max) return max;
|
||||
if(value < min) return min;
|
||||
if (value <= max && value >= min) return value;
|
||||
if (value > max) return max;
|
||||
if (value < min) return min;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -109,8 +109,8 @@ export const Util = {
|
||||
let nodes = [...layoutGroup.node, ...layoutGroup.marker],
|
||||
edges = layoutGroup.link;
|
||||
|
||||
return {
|
||||
nodes: nodes.map(item => item.getG6ModelProps()) as NodeConfig[],
|
||||
return {
|
||||
nodes: nodes.map(item => item.getG6ModelProps()) as NodeConfig[],
|
||||
edges: edges.map(item => item.getG6ModelProps()) as EdgeConfig[]
|
||||
};
|
||||
},
|
||||
@ -135,6 +135,12 @@ export const Util = {
|
||||
const Mat3 = G6Util.mat3;
|
||||
Mat3.rotate(matrix, matrix, rotation);
|
||||
return matrix;
|
||||
},
|
||||
|
||||
registerShape(shapeName: string, shapeDefinition, extendShapeType?: string) {
|
||||
// 不定义update,g6的自定义节点里面的update好像有bug
|
||||
shapeDefinition.update = undefined;
|
||||
return registerNode(shapeName, shapeDefinition, extendShapeType);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -164,6 +164,18 @@ export class SVModel {
|
||||
this.set('style', { matrix });
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否被选中的状态
|
||||
* @param isSelected
|
||||
*/
|
||||
setSelectedState(isSelected: boolean) {
|
||||
if(this.G6Item === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.G6Item.setState('selected', isSelected);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
@ -186,6 +198,8 @@ export class SVModel {
|
||||
isNode(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -76,6 +76,21 @@ export class SVNode extends SVModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否被选中的状态
|
||||
* @param isSelected
|
||||
*/
|
||||
setSelectedState(isSelected: boolean) {
|
||||
if (this.G6Item === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.G6Item.setState('selected', isSelected);
|
||||
this.appendages.forEach(item => {
|
||||
item.setSelectedState(isSelected);
|
||||
});
|
||||
}
|
||||
|
||||
getSourceId(): string {
|
||||
return this.sourceId;
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ export class SVFreedLabel extends SVNodeAppendage {
|
||||
},
|
||||
size: [0, 0],
|
||||
style: {
|
||||
opacity: 0,
|
||||
stroke: null,
|
||||
fill: 'transparent'
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ export class ModelConstructor {
|
||||
indexLabel: indexLabelList,
|
||||
link: [],
|
||||
marker: markerList,
|
||||
options: options,
|
||||
options,
|
||||
layoutCreator,
|
||||
modelList: [
|
||||
...nodeList,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import G6 from '@antv/g6';
|
||||
import { Util } from "../Common/util";
|
||||
|
||||
|
||||
export default G6.registerNode('array-node', {
|
||||
export default Util.registerShape('array-node', {
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0.5, 0],
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { registerNode } from '@antv/g6';
|
||||
import { Util } from '../Common/util';
|
||||
|
||||
|
||||
export default registerNode('binary-tree-node', {
|
||||
export default Util.registerShape('binary-tree-node', {
|
||||
draw(cfg, group) {
|
||||
cfg.size = cfg.size;
|
||||
|
||||
const width = cfg.size[0],
|
||||
height = cfg.size[1];
|
||||
height = cfg.size[1];
|
||||
|
||||
const wrapperRect = group.addShape('rect', {
|
||||
attrs: {
|
||||
@ -27,7 +27,7 @@ export default registerNode('binary-tree-node', {
|
||||
y: height / 2,
|
||||
width: width / 2,
|
||||
height: height,
|
||||
fill: cfg.color || cfg.style.fill,
|
||||
fill: cfg.style.fill,
|
||||
stroke: cfg.style.stroke || '#333',
|
||||
cursor: cfg.style.cursor
|
||||
},
|
||||
@ -64,4 +64,4 @@ export default registerNode('binary-tree-node', {
|
||||
[0.125, 0.5]
|
||||
];
|
||||
},
|
||||
});
|
||||
}, 'rect');
|
||||
@ -1,7 +1,36 @@
|
||||
import { registerNode, Util } from '@antv/g6';
|
||||
import G6 from "@antv/g6";
|
||||
import { Util } from "../Common/util";
|
||||
|
||||
|
||||
export default registerNode('clen-queue-pointer', {
|
||||
|
||||
|
||||
export default function rotate(shape, angle, transform) {
|
||||
const matrix1 = shape.getMatrix();
|
||||
const newMatrix1 = transform(matrix1, [
|
||||
['r', angle],
|
||||
]);
|
||||
shape.setMatrix(newMatrix1);
|
||||
}
|
||||
function translate(shape, x, y, transform) {
|
||||
const matrix1 = shape.getMatrix();
|
||||
const newMatrix1 = transform(matrix1, [
|
||||
['t', x, y],
|
||||
]);
|
||||
shape.setMatrix(newMatrix1);
|
||||
}
|
||||
function culcuRotate(angle, R) {
|
||||
let offsetX = Math.cos(angle) * R;
|
||||
let offsetY = -Math.sin(angle) * R;
|
||||
console.log(offsetX, offsetY, R);
|
||||
return {
|
||||
offsetX,
|
||||
offsetY,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Util.registerShape('clen-queue-pointer', {
|
||||
draw(cfg, group) {
|
||||
let id = cfg.id as string;
|
||||
|
||||
@ -55,10 +84,10 @@ export default registerNode('clen-queue-pointer', {
|
||||
});
|
||||
|
||||
// rotate(text, angle, G6.Util.transform);
|
||||
translate(text, 0, -75, Util.transform);
|
||||
translate(text, 0, -75, G6.Util.transform);
|
||||
}
|
||||
rotate(keyShape, angle, Util.transform);
|
||||
translate(keyShape, 0, -75, Util.transform);
|
||||
rotate(keyShape, angle, G6.Util.transform);
|
||||
translate(keyShape, 0, -75, G6.Util.transform);
|
||||
|
||||
return keyShape;
|
||||
|
||||
@ -89,26 +118,3 @@ export default registerNode('clen-queue-pointer', {
|
||||
});
|
||||
|
||||
|
||||
function rotate(shape, angle, transform) {
|
||||
const matrix1 = shape.getMatrix();
|
||||
const newMatrix1 = transform(matrix1, [
|
||||
['r', angle],
|
||||
]);
|
||||
shape.setMatrix(newMatrix1);
|
||||
}
|
||||
function translate(shape, x, y, transform) {
|
||||
const matrix1 = shape.getMatrix();
|
||||
const newMatrix1 = transform(matrix1, [
|
||||
['t', x, y],
|
||||
]);
|
||||
shape.setMatrix(newMatrix1);
|
||||
}
|
||||
function culcuRotate(angle, R) {
|
||||
let offsetX = Math.cos(angle) * R;
|
||||
let offsetY = -Math.sin(angle) * R;
|
||||
console.log(offsetX, offsetY, R);
|
||||
return {
|
||||
offsetX,
|
||||
offsetY,
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { registerNode } from '@antv/g6';
|
||||
import { Util } from '../Common/util';
|
||||
|
||||
|
||||
export default registerNode('cursor', {
|
||||
export default Util.registerShape('cursor', {
|
||||
draw(cfg, group) {
|
||||
const keyShape = group.addShape('path', {
|
||||
attrs: {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { registerNode } from '@antv/g6';
|
||||
import { Util } from "../Common/util";
|
||||
|
||||
|
||||
export default registerNode('link-list-node', {
|
||||
|
||||
export default Util.registerShape('link-list-node', {
|
||||
draw(cfg, group) {
|
||||
cfg.size = cfg.size || [30, 10];
|
||||
|
||||
@ -66,4 +67,4 @@ export default registerNode('link-list-node', {
|
||||
[0, 0.5]
|
||||
];
|
||||
}
|
||||
});
|
||||
}, 'rect');
|
||||
@ -1,7 +1,7 @@
|
||||
import { registerNode } from '@antv/g6';
|
||||
import { Util } from '../Common/util';
|
||||
|
||||
|
||||
export default registerNode('pointer', {
|
||||
export default Util.registerShape('pointer', {
|
||||
draw(cfg, group) {
|
||||
const keyShape = group.addShape('path', {
|
||||
attrs: {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { registerNode } from '@antv/g6';
|
||||
import { Util } from '../Common/util';
|
||||
|
||||
|
||||
export default registerNode('tri-tree-node', {
|
||||
export default Util.registerShape('tri-tree-node', {
|
||||
draw(cfg, group) {
|
||||
cfg.size = cfg.size;
|
||||
|
||||
@ -97,4 +97,4 @@ export default registerNode('tri-tree-node', {
|
||||
[0.5, 0.125]
|
||||
];
|
||||
},
|
||||
});
|
||||
}, 'rect');
|
||||
@ -1,8 +1,8 @@
|
||||
import { registerNode } from '@antv/g6';
|
||||
import { Util } from '../Common/util';
|
||||
|
||||
|
||||
|
||||
export default registerNode('two-cell-node', {
|
||||
export default Util.registerShape('two-cell-node', {
|
||||
draw(cfg, group) {
|
||||
cfg.size = cfg.size || [30, 10];
|
||||
|
||||
@ -99,4 +99,4 @@ export default registerNode('two-cell-node', {
|
||||
[0, 0.5]
|
||||
];
|
||||
}
|
||||
});
|
||||
}, 'rect');
|
||||
@ -1,7 +1,7 @@
|
||||
import { Engine } from "./engine";
|
||||
import { Bound } from "./Common/boundingRect";
|
||||
import { Group } from "./Common/group";
|
||||
import G6, { Util } from '@antv/g6';
|
||||
import G6 from '@antv/g6';
|
||||
import Pointer from "./RegisteredShape/pointer";
|
||||
import LinkListNode from "./RegisteredShape/linkListNode";
|
||||
import BinaryTreeNode from "./RegisteredShape/binaryTreeNode";
|
||||
@ -11,8 +11,11 @@ import ArrayNode from "./RegisteredShape/arrayNode";
|
||||
import Cursor from "./RegisteredShape/cursor";
|
||||
import { Vector } from "./Common/vector";
|
||||
import { EngineOptions, LayoutCreator } from "./options";
|
||||
import { SVNode } from "./Model/SVNode";
|
||||
import { SourceNode } from "./sources";
|
||||
import { Util } from "./Common/util";
|
||||
import { SVModel } from "./Model/SVModel";
|
||||
|
||||
|
||||
|
||||
|
||||
export interface StructV {
|
||||
@ -45,7 +48,7 @@ export const SV: StructV = function(DOMContainer: HTMLElement, engineOptions: En
|
||||
SV.Group = Group;
|
||||
SV.Bound = Bound;
|
||||
SV.Vector = Vector;
|
||||
SV.Mat3 = Util.mat3;
|
||||
SV.Mat3 = G6.Util.mat3;
|
||||
SV.G6 = G6;
|
||||
|
||||
SV.registeredLayout = {};
|
||||
@ -59,7 +62,7 @@ SV.registeredShape = [
|
||||
CLenQueuePointer,
|
||||
];
|
||||
|
||||
SV.registerShape = G6.registerNode;
|
||||
SV.registerShape = Util.registerShape;
|
||||
SV.registerLayout = function(name: string, layoutCreator: LayoutCreator) {
|
||||
|
||||
if(typeof layoutCreator.sourcesPreprocess !== 'function') {
|
||||
@ -69,8 +72,8 @@ SV.registerLayout = function(name: string, layoutCreator: LayoutCreator) {
|
||||
}
|
||||
|
||||
if(typeof layoutCreator.defineLeakRule !== 'function') {
|
||||
layoutCreator.defineLeakRule = function(nodes: SVNode[]): SVNode[] {
|
||||
return nodes;
|
||||
layoutCreator.defineLeakRule = function(models: SVModel[]): SVModel[] {
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,4 +84,3 @@ SV.registerLayout = function(name: string, layoutCreator: LayoutCreator) {
|
||||
SV.registeredLayout[name] = layoutCreator;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -266,6 +266,8 @@ export class Reconcile {
|
||||
timingFunction
|
||||
});
|
||||
}
|
||||
|
||||
item.G6Item.enableCapture(false);
|
||||
});
|
||||
|
||||
EventBus.emit('onLeak', leakModels);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Engine } from '../engine';
|
||||
import { SVModel } from '../Model/SVModel';
|
||||
import { Util } from '../Common/util';
|
||||
import { Tooltip, Graph, GraphData } from '@antv/g6';
|
||||
import { InitViewBehaviors } from '../BehaviorHelper/initViewBehaviors';
|
||||
import { Tooltip, Graph, GraphData, Modes } from '@antv/g6';
|
||||
import { InitG6Behaviors } from '../BehaviorHelper/initG6Behaviors';
|
||||
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ export class Renderer {
|
||||
private g6Instance: Graph; // g6 实例
|
||||
private shadowG6Instance: Graph;
|
||||
|
||||
constructor(engine: Engine, DOMContainer: HTMLElement) {
|
||||
constructor(engine: Engine, DOMContainer: HTMLElement, behaviorsModes: Modes) {
|
||||
this.engine = engine;
|
||||
|
||||
const enable: boolean = this.engine.animationOptions.enable,
|
||||
@ -53,9 +53,7 @@ export class Renderer {
|
||||
easing: timingFunction
|
||||
},
|
||||
fitView: false,
|
||||
modes: {
|
||||
default: InitViewBehaviors()
|
||||
},
|
||||
modes: behaviorsModes,
|
||||
plugins: [tooltip]
|
||||
});
|
||||
}
|
||||
@ -69,7 +67,7 @@ export class Renderer {
|
||||
private getTooltipContent(model: SVModel, items: { [key: string]: string }): HTMLDivElement {
|
||||
const wrapper = document.createElement('div');
|
||||
|
||||
if(model === null || model === undefined) {
|
||||
if (model === null || model === undefined) {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
||||
@ -5,12 +5,12 @@ import { Util } from "../Common/util";
|
||||
import { SVModel } from "../Model/SVModel";
|
||||
import { Renderer } from "./renderer";
|
||||
import { Reconcile } from "./reconcile";
|
||||
import { FixNodeMarkerDrag } from "../BehaviorHelper/fixNodeMarkerDrag";
|
||||
import { InitDragCanvasWithLeak } from "../BehaviorHelper/dragCanvasWithLeak";
|
||||
import { EventBus } from "../Common/eventBus";
|
||||
import { InitZoomCanvasWithLeak } from "../BehaviorHelper/zoomCanvasWithLeak";
|
||||
import { Group } from "../Common/group";
|
||||
import { Graph } from "_@antv_g6-pc@0.5.0@@antv/g6-pc";
|
||||
import { Graph, Modes } from "@antv/g6-pc";
|
||||
import { InitG6Behaviors } from "../BehaviorHelper/initG6Behaviors";
|
||||
import { SVNode } from "../Model/SVNode";
|
||||
import { SolveBrushSelectDrag, SolveDragCanvasWithLeak, SolveNodeAppendagesDrag, SolveZoomCanvasWithLeak } from "../BehaviorHelper/behaviorIssueHelper";
|
||||
|
||||
|
||||
|
||||
@ -26,33 +26,35 @@ export class ViewContainer {
|
||||
|
||||
public hasLeak: boolean;
|
||||
public leakAreaY: number;
|
||||
public brushSelectedModels: SVModel[]; // 保存框选过程中被选中的节点
|
||||
public clickSelectNode: SVNode; // 点击选中的节点
|
||||
|
||||
|
||||
constructor(engine: Engine, DOMContainer: HTMLElement) {
|
||||
const behaviorsModes: Modes = InitG6Behaviors(engine, this);
|
||||
|
||||
this.engine = engine;
|
||||
this.layoutProvider = new LayoutProvider(engine, this);
|
||||
this.renderer = new Renderer(engine, DOMContainer);
|
||||
this.renderer = new Renderer(engine, DOMContainer, behaviorsModes);
|
||||
this.reconcile = new Reconcile(engine, this.renderer);
|
||||
this.prevLayoutGroupTable = new Map();
|
||||
this.prevModelList = [];
|
||||
this.accumulateLeakModels = [];
|
||||
this.hasLeak = false; // 判断是否已经发生过泄漏
|
||||
this.brushSelectedModels = [];
|
||||
this.clickSelectNode = null;
|
||||
|
||||
const g6Instance = this.renderer.getG6Instance(),
|
||||
leakAreaHeight = this.engine.viewOptions.leakAreaHeight,
|
||||
height = this.getG6Instance().getHeight(),
|
||||
{ drag, zoom } = this.engine.interactionOptions;
|
||||
{ drag, zoom } = this.engine.behaviorOptions;
|
||||
|
||||
this.leakAreaY = height - leakAreaHeight;
|
||||
|
||||
if (drag) {
|
||||
InitDragCanvasWithLeak(this);
|
||||
}
|
||||
|
||||
if (zoom) {
|
||||
// InitZoomCanvasWithLeak(this);
|
||||
}
|
||||
|
||||
FixNodeMarkerDrag(g6Instance);
|
||||
SolveNodeAppendagesDrag(this);
|
||||
SolveBrushSelectDrag(this);
|
||||
drag && SolveDragCanvasWithLeak(this);
|
||||
zoom && SolveZoomCanvasWithLeak(this);
|
||||
}
|
||||
|
||||
|
||||
@ -93,6 +95,13 @@ export class ViewContainer {
|
||||
return this.accumulateLeakModels;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
getLayoutGroupTable(): LayoutGroupTable {
|
||||
return this.prevLayoutGroupTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新视图
|
||||
*/
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Sources } from "./sources";
|
||||
import { ModelConstructor } from "./Model/modelConstructor";
|
||||
import { AnimationOptions, EngineOptions, InteractionOptions, LayoutGroupOptions, LayoutOptions, ViewOptions } from "./options";
|
||||
import { LayoutGroupTable, ModelConstructor } from "./Model/modelConstructor";
|
||||
import { AnimationOptions, BehaviorOptions, EngineOptions, LayoutGroupOptions, ViewOptions } from "./options";
|
||||
import { EventBus } from "./Common/eventBus";
|
||||
import { ViewContainer } from "./View/viewContainer";
|
||||
import { SVNode } from "./Model/SVNode";
|
||||
@ -11,13 +11,12 @@ import { SVModel } from "./Model/SVModel";
|
||||
export class Engine {
|
||||
private modelConstructor: ModelConstructor;
|
||||
private viewContainer: ViewContainer;
|
||||
private prevSource: Sources;
|
||||
private prevStringSource: string;
|
||||
|
||||
public engineOptions: EngineOptions;
|
||||
public viewOptions: ViewOptions;
|
||||
public animationOptions: AnimationOptions;
|
||||
public interactionOptions: InteractionOptions;
|
||||
public behaviorOptions: BehaviorOptions;
|
||||
|
||||
constructor(DOMContainer: HTMLElement, engineOptions: EngineOptions) {
|
||||
this.engineOptions = Object.assign({}, engineOptions);
|
||||
@ -36,12 +35,12 @@ export class Engine {
|
||||
timingFunction: 'easePolyOut'
|
||||
}, engineOptions.animation);
|
||||
|
||||
this.interactionOptions = Object.assign({
|
||||
this.behaviorOptions = Object.assign({
|
||||
drag: true,
|
||||
zoom: true,
|
||||
dragNode: true,
|
||||
selectNode: true
|
||||
}, engineOptions.interaction);
|
||||
}, engineOptions.behavior);
|
||||
|
||||
this.modelConstructor = new ModelConstructor(this);
|
||||
this.viewContainer = new ViewContainer(this, DOMContainer);
|
||||
@ -62,7 +61,6 @@ export class Engine {
|
||||
return;
|
||||
}
|
||||
|
||||
this.prevSource = source;
|
||||
this.prevStringSource = stringSource;
|
||||
|
||||
// 1 转换模型(data => model)
|
||||
@ -199,6 +197,15 @@ export class Engine {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启/关闭框选模式
|
||||
* @param enable
|
||||
*/
|
||||
public switchBrushSelect(enable: boolean) {
|
||||
const g6Instance = this.viewContainer.getG6Instance();
|
||||
enable ? g6Instance.setMode('brush') : g6Instance.setMode('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁引擎
|
||||
*/
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SVModel } from "./Model/SVModel";
|
||||
import { SVNode } from "./Model/SVNode";
|
||||
import { SourceNode } from "./sources";
|
||||
|
||||
@ -86,6 +87,9 @@ export interface LayoutGroupOptions {
|
||||
addressLabel?: AddressLabelOption;
|
||||
indexLabel?: { [key: string]: IndexLabelOption };
|
||||
layout?: LayoutOptions;
|
||||
behavior?: {
|
||||
dragNode: boolean | string[];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -110,7 +114,7 @@ export interface AnimationOptions {
|
||||
};
|
||||
|
||||
|
||||
export interface InteractionOptions {
|
||||
export interface BehaviorOptions {
|
||||
drag: boolean;
|
||||
zoom: boolean;
|
||||
}
|
||||
@ -118,14 +122,14 @@ export interface InteractionOptions {
|
||||
export interface EngineOptions {
|
||||
view?: ViewOptions;
|
||||
animation?: AnimationOptions;
|
||||
interaction?: InteractionOptions;
|
||||
behavior?: BehaviorOptions;
|
||||
};
|
||||
|
||||
|
||||
export interface LayoutCreator {
|
||||
defineOptions(sourceData: SourceNode[]): LayoutGroupOptions;
|
||||
sourcesPreprocess?(sourceData: SourceNode[], options: LayoutGroupOptions): SourceNode[];
|
||||
defineLeakRule?(nodes: SVNode[]): SVNode[];
|
||||
defineLeakRule?(models: SVModel[]): SVModel[];
|
||||
layout(nodes: SVNode[], layoutOptions: LayoutOptions);
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@ -17,5 +17,6 @@ module.exports = {
|
||||
loader: 'ts-loader'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// devtool: 'eval-source-map'
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user