feat: 重写泄漏区逻辑

This commit is contained in:
黎智洲
2022-03-02 22:07:27 +08:00
parent 5893ef2938
commit 3170bd77ec
21 changed files with 2209 additions and 1999 deletions
+32 -21
View File
@@ -1,11 +1,11 @@
SV.registerLayout('BinaryTree', {
defineOptions() {
return {
element: {
node: {
default: {
type: 'binary-tree-node',
size: [60, 30],
label: '[data]',
label: '[id]',
style: {
fill: '#b83b5e',
stroke: '#333',
@@ -58,7 +58,7 @@ SV.registerLayout('BinaryTree', {
/**
* 对子树进行递归布局
*/
layoutItem(node, parent, index, layoutOptions) {
layoutItem(node, layoutOptions) {
// 次双亲不进行布局
if (!node) {
return null;
@@ -69,43 +69,54 @@ SV.registerLayout('BinaryTree', {
height = bound.height,
group = new Group(node),
leftGroup = null,
rightGroup = null;
rightGroup = null,
leftBound = null,
rightBound = null;
if (node.visited) {
return null;
}
if (node.child && node.child[0]) {
leftGroup = this.layoutItem(node.child[0], node, 0, layoutOptions);
leftGroup = this.layoutItem(node.child[0], layoutOptions);
}
if (node.child && node.child[1]) {
rightGroup = this.layoutItem(node.child[1], node, 1, layoutOptions);
rightGroup = this.layoutItem(node.child[1], layoutOptions);
}
// 处理左右子树相交问题
if (leftGroup && rightGroup) {
let intersection = Bound.intersect(leftGroup.getBound(), rightGroup.getBound()),
move = 0;
if (leftGroup) {
leftBound = leftGroup.getBound();
node.set('y', leftBound.y - layoutOptions.yInterval - height);
}
if (intersection && intersection.width > 0) {
move = (intersection.width + layoutOptions.xInterval) / 2;
leftGroup.translate(-move, 0);
rightGroup.translate(move, 0);
if(rightGroup) {
rightBound = rightGroup.getBound();
if(leftGroup) {
rightGroup.translate(0, leftBound.y - rightBound.y)
}
rightBound = rightGroup.getBound();
node.set('y', rightBound.y - layoutOptions.yInterval - height);
}
// 处理左右子树相交问题
if (leftGroup && rightGroup) {
let move = Math.abs(rightBound.x - layoutOptions.xInterval - leftBound.x - leftBound.width);
if (move > 0) {
leftGroup.translate(-move / 2, 0);
rightGroup.translate(move / 2, 0);
}
}
if (leftGroup) {
let leftBound = leftGroup.getBound();
node.set('y', leftBound.y - layoutOptions.yInterval - height);
leftBound = leftGroup.getBound();
node.set('x', leftBound.x + leftBound.width + layoutOptions.xInterval / 2 - width);
}
if(rightGroup) {
let rightBound = rightGroup.getBound();
node.set('y', rightBound.y - layoutOptions.yInterval - height);
rightBound = rightGroup.getBound();
node.set('x', rightBound.x - layoutOptions.xInterval / 2 - width);
}
@@ -129,7 +140,7 @@ SV.registerLayout('BinaryTree', {
*/
layout(elements, layoutOptions) {
let root = elements[0];
this.layoutItem(root, null, -1, layoutOptions);
this.layoutItem(root, layoutOptions);
},
});
+25 -13
View File
@@ -77,25 +77,37 @@ SV.registerLayout('LinkList', {
layout: {
xInterval: 50,
yInterval: 50
},
behavior: {
dragNode: false
}
};
},
layout(elements, layoutOptions) {
for (let i = 0; i < elements.length; i++) {
let node = elements[i],
prev = elements[1 - 1],
width = node.get('size')[0];
if (prev) {
node.set('y', prev.get('y'));
node.set('x', prev.get('x') + layoutOptions.xInterval + width);
}
/**
* 对子树进行递归布局
* @param node
* @param parent
*/
layoutItem(node, prev, layoutOptions) {
if (!node) {
return null;
}
let width = node.get('size')[0];
if (prev) {
node.set('y', prev.get('y'));
node.set('x', prev.get('x') + layoutOptions.xInterval + width);
}
if (node.next) {
this.layoutItem(node.next, node, layoutOptions);
}
},
layout(elements, layoutOptions) {
let root = elements[0];
this.layoutItem(root, null, layoutOptions);
}
});
+1 -1
View File
@@ -20,7 +20,7 @@
element: {
default: {
type: 'link-list-node',
label: '[id]',
label: '[data]',
size: [60, 30],
style: {
stroke: '#333',
+120
View File
@@ -0,0 +1,120 @@
const SOURCES_DATA = [
{
LinkList0: {
data: [
{
id: '0x617eb0',
data: 'Z',
next: '0x617ef0',
rootExternal: ['L'],
type: 'default',
},
{
id: '0x617ef0',
data: 'A',
next: '0x617f10',
type: 'default',
},
{
id: '0x617f10',
data: 'B',
next: '0x617f30',
type: 'default',
},
{
id: '0x617f30',
data: 'C',
external: ['r', 't'],
next: null,
type: 'default',
},
],
layouter: 'LinkList',
},
LinkList1: {
data: [
{
id: '0x617ed0',
data: 'Y',
next: '0x617f50',
rootExternal: ['L2'],
type: 'default',
},
{
id: '0x617f50',
data: 'a',
next: '0x617f70',
type: 'default',
},
{
id: '0x617f70',
data: 'b',
external: ['r2', 't2'],
loopNext: 'LinkList0#0x617f30',
type: 'default',
},
],
layouter: 'LinkList',
},
isEnterFunction: false,
},
{
LinkList0: {
data: [
{
id: '0x617eb0',
data: 'Z',
next: '0x617ef0',
rootExternal: ['L'],
type: 'default',
},
{
id: '0x617ef0',
data: 'A',
next: '0x617f10',
type: 'default',
},
{
id: '0x617f10',
data: 'B',
next: '0x617f30',
type: 'default',
},
{
id: '0x617f30',
data: 'C',
external: ['r', 't'],
next: null,
type: 'default',
},
],
layouter: 'LinkList',
},
LinkList1: {
data: [
{
id: '0x617ed0',
data: 'Y',
next: '0x617f50',
rootExternal: ['L2'],
type: 'default',
},
{
id: '0x617f50',
data: 'a',
next: '0x617f70',
type: 'default',
},
{
id: '0x617f70',
data: 'b',
external: ['r2', 't2'],
next: null,
type: 'default',
},
],
layouter: 'LinkList',
},
isEnterFunction: false,
},
];
+128 -214
View File
@@ -1,237 +1,151 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DEMO</title>
<style>
* {
padding: 0;
margin: 0;
user-select: none;
}
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DEMO</title>
<style>
* {
padding: 0;
margin: 0;
user-select: none;
}
.container {
background-color: #fafafa;
border: 1px solid #ccc;
position: relative;
}
.down {
display: flex;
margin-top: 20px;
}
#container {
width: 100%;
height: 500px;
position: relative;
overflow: hidden;
}
#leak {
position: absolute;
left: 0;
opacity: 0;
top: 100px;
width: 100%;
box-sizing: border-box;
padding: 4px;
border-top: 1px dashed #000;
pointer-events: none;
transition: opacity 0.75s ease-in-out;
}
#leak>span {
color: #000;
}
</style>
</head>
.container {
background-color: #fafafa;
border: 1px solid #ccc;
position: relative;
}
<body>
<div class="container" id="container">
<div id="leak">
<span>泄漏区</span>
</div>
</div>
.down {
display: flex;
margin-top: 20px;
}
<button id="btn-prev">prev</button>
<button id="btn-next">next</button>
<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>
#container {
width: 100%;
height: 500px;
position: relative;
overflow: hidden;
}
<script src="./../dist/sv.js"></script>
<script>
const Group = SV.Group,
Bound = SV.Bound,
G6 = SV.G6,
Vector = SV.Vector;
</script>
<script src="./Layouter/LinkList.js"></script>
<script src="./Layouter/BinaryTree.js"></script>
<script src="./Layouter/Stack.js"></script>
<script src="./Layouter/LinkQueue.js"></script>
<script src="./Layouter/GeneralizedList.js"></script>
<script src="./Layouter/ChainHashTable.js"></script>
<script src="./Layouter/Array.js"></script>
<script src="./Layouter/HashTable.js"></script>
<script src="./Layouter/LinkStack.js"></script>
<script src="./Layouter/AdjoinMatrixGraph.js"></script>
<script src="./Layouter/AdjoinTableGraph.js"></script>
<script src="./Layouter/SqQueue.js"></script>
<script src="./Layouter/PTree.js"></script>
<script src="./Layouter/PCTree.js"></script>
#leak {
position: absolute;
left: 0;
opacity: 0;
top: 100px;
width: 100%;
box-sizing: border-box;
padding: 4px;
border-top: 1px dashed #000;
pointer-events: none;
transition: opacity 0.75s ease-in-out;
}
<script>
let cur = SV(document.getElementById('container'), {
view: {
leakAreaHeight: 130,
groupPadding: 40,
},
});
#leak > span {
color: #000;
}
</style>
</head>
let data = [{
"BinaryTree0": {
"data": [{
"external": [
"T1",
"r"
],
"child": [
"0x617ee0",
"0x617f10"
],
"id": "0x617eb0",
"name": "T1",
"data": "Z",
"root": true,
"type": "default"
}, {
"child": [
"0x0",
"0x0"
],
"id": "0x617ee0",
"name": "T1->lchild",
"data": "A",
"type": "default"
}, {
"child": [
"0x0",
"0x617f40"
],
"id": "0x617f10",
"name": "T1->rchild",
"data": "B",
"type": "default",
"external": [
"t"
]
}, ],
"layouter": "BinaryTree"
},
"isEnterFunction": false
}, {
"BinaryTree1": {
"data": [{
"external": [
"T1",
"r"
],
"child": [
"0x617ee0",
"0x617f10"
],
"id": "0x617eb0",
"name": "T1",
"data": "Z",
"root": true,
"type": "default"
}, {
"child": [
"0x0",
"0x0"
],
"id": "0x617ee0",
"name": "T1->lchild",
"data": "A",
freed: 'freed',
"type": "default"
}, {
"child": [
"0x0",
"0x617f40"
],
"id": "0x617f10",
"name": "T1->rchild",
"data": "B",
"type": "default",
"external": [
"t"
]
}, ],
"layouter": "BinaryTree"
},
"isEnterFunction": false
}, ];
<body>
<div class="container" id="container">
<div id="leak">
<span>泄漏区</span>
</div>
</div>
let dataIndex = 0,
curData = data[dataIndex];
<button id="btn-prev">prev</button>
<button id="btn-next">next</button>
<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>
let enableBrushSelect = false;
<script src="./../dist/sv.js"></script>
<script>
const Group = SV.Group,
Bound = SV.Bound,
G6 = SV.G6,
Vector = SV.Vector;
</script>
<script src="./Layouter/LinkList.js"></script>
<script src="./Layouter/BinaryTree.js"></script>
<script src="./Layouter/Stack.js"></script>
<script src="./Layouter/LinkQueue.js"></script>
<script src="./Layouter/GeneralizedList.js"></script>
<script src="./Layouter/ChainHashTable.js"></script>
<script src="./Layouter/Array.js"></script>
<script src="./Layouter/HashTable.js"></script>
<script src="./Layouter/LinkStack.js"></script>
<script src="./Layouter/AdjoinMatrixGraph.js"></script>
<script src="./Layouter/AdjoinTableGraph.js"></script>
<script src="./Layouter/SqQueue.js"></script>
<script src="./Layouter/PTree.js"></script>
<script src="./Layouter/PCTree.js"></script>
<script src="./data.js"></script>
const container = document.getElementById('container'),
pos = document.getElementById('pos');
<script>
let cur = SV(document.getElementById('container'), {
view: {
leakAreaHeight: 130,
groupPadding: 40,
},
});
const leak = document.getElementById('leak');
let dataIndex = 0,
curData = SOURCES_DATA[dataIndex];
cur.render(curData);
let enableBrushSelect = false;
document.getElementById('btn-next').addEventListener('click', e => {
curData = data[++dataIndex];
cur.render(curData);
});
const container = document.getElementById('container'),
pos = document.getElementById('pos');
document.getElementById('btn-prev').addEventListener('click', e => {
curData = data[--dataIndex];
cur.render(curData);
});
const leak = document.getElementById('leak');
document.getElementById('resize').addEventListener('click', e => {
container.style.height = 800 + 'px';
cur.resize(container.offsetWidth, container.offsetHeight);
});
cur.render(curData);
document.getElementById('relayout').addEventListener('click', e => {
cur.reLayout();
});
document.getElementById('btn-next').addEventListener('click', e => {
curData = SOURCES_DATA[++dataIndex];
cur.render(curData);
});
document.getElementById('switch-mode').addEventListener('click', e => {
cur.updateStyle('Array', newArrayOption);
});
document.getElementById('btn-prev').addEventListener('click', e => {
curData = SOURCES_DATA[--dataIndex];
cur.render(curData);
});
document.getElementById('brush-select').addEventListener('click', e => {
enableBrushSelect = !enableBrushSelect;
cur.switchBrushSelect(enableBrushSelect);
});
document.getElementById('resize').addEventListener('click', e => {
container.style.height = 800 + 'px';
cur.resize(container.offsetWidth, container.offsetHeight);
});
cur.on('onLeakAreaUpdate', payload => {
leak.style.opacity = payload.hasLeak ? 1 : 0;
leak.style.top = payload.leakAreaY - 40 + 'px';
});
document.getElementById('relayout').addEventListener('click', e => {
cur.reLayout();
});
// -------------------------------------------------------------------------------------------------------
document.getElementById('switch-mode').addEventListener('click', e => {
cur.updateStyle('Array', newArrayOption);
});
container.addEventListener('mousemove', e => {
let x = e.offsetX,
y = e.offsetY;
pos.innerHTML = `${x},${y}`;
});
</script>
</body>
document.getElementById('brush-select').addEventListener('click', e => {
enableBrushSelect = !enableBrushSelect;
cur.switchBrushSelect(enableBrushSelect);
});
</html>
cur.on('onLeakAreaUpdate', payload => {
leak.style.opacity = payload.hasLeak ? 1 : 0;
leak.style.top = payload.leakAreaY - 40 + 'px';
});
// -------------------------------------------------------------------------------------------------------
container.addEventListener('mousemove', e => {
let x = e.offsetX,
y = e.offsetY;
pos.innerHTML = `${x},${y}`;
});
</script>
</body>
</html>