From 4c1510da1ffc69bd9d5ac6afa1b1b5a22ce9fb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=8E=E6=99=BA=E6=B4=B2?= <1543046129@qq.com> Date: Mon, 17 May 2021 14:02:19 +0800 Subject: [PATCH] =?UTF-8?q?feature=EF=BC=9A=E6=B7=BB=E5=8A=A0=E6=B3=84?= =?UTF-8?q?=E6=BC=8F=E5=8C=BA=E5=8A=9F=E8=83=BD=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/dataStruct/Array.js | 24 +-- demo/dataStruct/BinaryTree.js | 7 +- demo/dataStruct/ChainHashTable.js | 27 ++- demo/dataStruct/GeneralizedList.js | 215 ++++++++++++++++++++++ demo/dataStruct/LinkQueue.js | 234 +++++++++++++----------- demo/dataStruct/linkList.js | 34 ++-- demo/demo.html | 61 ++++++- dist/sv.js | 2 +- src/{View => Behavior.ts}/behavior.ts | 33 +++- src/{View => Common}/boundingRect.ts | 2 +- src/{View => Common}/group.ts | 6 +- src/Common/util.ts | 33 ++-- src/Model/modelConstructor.ts | 93 +++++----- src/Model/modelData.ts | 65 +++---- src/RegisteredShape/binaryTreeNode.ts | 4 +- src/RegisteredShape/indexedNode.ts | 58 ++++++ src/RegisteredShape/linkListNode.ts | 8 +- src/RegisteredShape/twoCellNode.ts | 3 +- src/StructV.ts | 15 +- src/View/animation.ts | 57 +++--- src/View/container/container.ts | 188 +++++++++++++++++++ src/View/container/freed.ts | 6 + src/View/container/leak.ts | 6 + src/View/container/main.ts | 80 ++++++++ src/View/layouter.ts | 110 ++++++----- src/View/renderer.ts | 254 ++++++-------------------- src/View/viewManager.ts | 212 +++++++++++++++++++++ src/engine.ts | 116 ++++++++---- src/options.ts | 10 +- src/sources.ts | 2 - 30 files changed, 1381 insertions(+), 584 deletions(-) create mode 100644 demo/dataStruct/GeneralizedList.js rename src/{View => Behavior.ts}/behavior.ts (81%) rename src/{View => Common}/boundingRect.ts (98%) rename src/{View => Common}/group.ts (93%) create mode 100644 src/RegisteredShape/indexedNode.ts create mode 100644 src/View/container/container.ts create mode 100644 src/View/container/freed.ts create mode 100644 src/View/container/leak.ts create mode 100644 src/View/container/main.ts create mode 100644 src/View/viewManager.ts diff --git a/demo/dataStruct/Array.js b/demo/dataStruct/Array.js index f85760d..a0c90b2 100644 --- a/demo/dataStruct/Array.js +++ b/demo/dataStruct/Array.js @@ -8,7 +8,7 @@ class Arrays extends Engine { return { element: { default: { - type: 'rect', + type: 'indexed-node', label: '[id]', size: [60, 30], style: { @@ -31,27 +31,26 @@ class Arrays extends Engine { }; } - layout(elements, layoutOptions) { - let arr = elements.default; + layout(elements) { + let arr = elements, + width = arr[0].get('size')[0]; for(let i = 0; i < arr.length; i++) { - let width = arr[i].get('size')[0]; - - if(i > 0) { - arr[i].set('x', arr[i - 1].get('x') + width); - } + arr[i].set('x', i * width); } } } + + const A = function(container) { return{ engine: new Arrays(container), data: [[ - { id: 1, external: 'A' }, - { id: 2 }, - { id: 3 }, + { id: 1, index: 0 }, + { id: 2, index: 1 }, + { id: 3, index: 2 }, { id: 4 }, { id: 5 }, { id: 6 }, @@ -66,7 +65,8 @@ const A = function(container) { { id: 3 }, { id: 6, external: 'A' }, { id: 7 }, - { id: 8 } + { id: 8 }, + { id: 12 } ]] } }; \ No newline at end of file diff --git a/demo/dataStruct/BinaryTree.js b/demo/dataStruct/BinaryTree.js index e195896..de03a4d 100644 --- a/demo/dataStruct/BinaryTree.js +++ b/demo/dataStruct/BinaryTree.js @@ -27,10 +27,7 @@ class BinaryTree extends Engine { stroke: '#333', lineAppendWidth: 6, cursor: 'pointer', - endArrow: { - path: G6.Arrow.triangle(8, 6, 0), - fill: '#333' - }, + endArrow: 'default', startArrow: { path: G6.Arrow.circle(2, -1), fill: '#333' @@ -130,7 +127,7 @@ class BinaryTree extends Engine { * @param {*} layoutOptions */ layout(elements, layoutOptions) { - let nodes = elements.default, + let nodes = elements, rootNodes = [], node, root, diff --git a/demo/dataStruct/ChainHashTable.js b/demo/dataStruct/ChainHashTable.js index 3638998..f014de2 100644 --- a/demo/dataStruct/ChainHashTable.js +++ b/demo/dataStruct/ChainHashTable.js @@ -107,7 +107,7 @@ layout(elements, layoutOptions) { - let headNode = elements.head; + let headNode = elements.filter(item => item.type === 'head'); for(let i = 0; i < headNode.length; i++) { let node = headNode[i], @@ -128,9 +128,9 @@ } -const CHT = function(container) { +const CHT = function(container, options) { return{ - engine: new ChainHashTable(container), + engine: new ChainHashTable(container, options), data: [ { head: [{ @@ -153,7 +153,26 @@ const CHT = function(container) { }] }, { - + head: [{ + id: 0, + start: 'node#0' + }, { + id: 2, + start: 'node#2' + }, { + id: 3, + start: 'node#4' + }], + node: [{ + id: 0, + next: 1 + }, { + id: 1 + },{ + id: 2 + },{ + id: 4 + }] } ] } diff --git a/demo/dataStruct/GeneralizedList.js b/demo/dataStruct/GeneralizedList.js new file mode 100644 index 0000000..d0ddc2b --- /dev/null +++ b/demo/dataStruct/GeneralizedList.js @@ -0,0 +1,215 @@ + + +SV.registerShape('three-cell-node', { + draw(cfg, group) { + cfg.size = cfg.size || [30, 10]; + + const width = cfg.size[0], + height = cfg.size[1]; + + const wrapperRect = group.addShape('rect', { + attrs: { + x: width / 2, + y: height / 2, + width: width, + height: height, + stroke: cfg.style.stroke, + fill: '#eee' + }, + name: 'wrapper', + draggable: true + }); + + group.addShape('rect', { + attrs: { + x: width / 2, + y: height / 2, + width: width / 3, + height: height, + fill: cfg.style.fill, + stroke: cfg.style.stroke + }, + name: 'left-rect', + draggable: true + }); + + group.addShape('rect', { + attrs: { + x: width * (5 / 6), + y: height / 2, + width: width / 3, + height: height, + fill: '#eee', + stroke: cfg.style.stroke + }, + name: 'mid-rect', + draggable: true + }); + + if (cfg.label) { + const style = (cfg.labelCfg && cfg.labelCfg.style) || {}; + group.addShape('text', { + attrs: { + x: width * (2 / 3), + y: height, + textAlign: 'center', + textBaseline: 'middle', + text: cfg.label, + fill: style.fill || '#000', + fontSize: style.fontSize || 16 + }, + name: 'text', + draggable: true + }); + } + + return wrapperRect; + }, + + getAnchorPoints() { + return [ + [0, 0.5], + [0.5, 0.5], + [0.5, 0], + [5 / 6, 0.5] + ]; + } +}); + + + +class GeneralizedList extends Engine { + + defineOptions() { + return { + element: { + tableNode: { + type: 'three-cell-node', + label: '[tag]', + size: [90, 30], + style: { + stroke: '#333', + fill: '#b83b5e' + } + }, + atomNode: { + type: 'two-cell-node', + label: '[tag]', + size: [60, 30], + style: { + stroke: '#333', + fill: '#b83b5e' + } + } + }, + link: { + sub: { + type: 'line', + sourceAnchor: 1, + targetAnchor: 2, + style: { + stroke: '#333', + endArrow: { + path: G6.Arrow.triangle(8, 6, 0), + fill: '#333' + }, + startArrow: { + path: G6.Arrow.circle(2, -1), + fill: '#333' + } + } + }, + next: { + type: 'line', + sourceAnchor: 3, + targetAnchor: 0, + style: { + stroke: '#333', + endArrow: { + path: G6.Arrow.triangle(8, 6, 0), + fill: '#333' + }, + startArrow: { + path: G6.Arrow.circle(2, -1), + fill: '#333' + } + } + } + }, + layout: { + xInterval: 40, + yInterval: 20, + } + }; + } + + /** + * 对子树进行递归布局 + * @param node + * @param parent + */ + layoutItem(node, prev, layoutOptions) { + let [width, height] = node.get('size'); + + 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); + } + + // 存在子节点 + if(node.sub) { + node.sub.set('y', node.get('y') + layoutOptions.yInterval + height); + + // 子结点还是广义表 + if(node.sub.tag === 1) { + node.sub.set('x', node.get('x')); + this.layoutItem(node.sub, null, layoutOptions); + } + else { + let subWidth = node.sub.get('size')[0]; + node.sub.set('x', node.get('x') + width - subWidth); + } + } + } + + layout(elements, layoutOptions) { + let tableNodes = elements.tableNode, + tableRootNode = null; + + for(let i = 0; i < tableNodes.length; i++) { + if(tableNodes[i].root) { + tableRootNode = tableNodes[i]; + break; + } + } + + if(tableRootNode) { + this.layoutItem(tableRootNode, null, layoutOptions); + } + } +} + + + +const GL = function(container) { + return{ + engine: new GeneralizedList(container), + data: [{ + "atomNode": [], + "tableNode": [ + { + "id": 6385328, + "tag": 1, + "root": true, + "external": [ + "gl" + ] + } + ] + }] + } +}; \ No newline at end of file diff --git a/demo/dataStruct/LinkQueue.js b/demo/dataStruct/LinkQueue.js index 0c66762..aca1022 100644 --- a/demo/dataStruct/LinkQueue.js +++ b/demo/dataStruct/LinkQueue.js @@ -1,94 +1,95 @@ -G6.registerNode('link-Queue-head', { - draw(cfg, group) { - cfg.size = cfg.size || [30, 10]; +// G6.registerNode('link-Queue-head', { +// draw(cfg, group) { +// cfg.size = cfg.size || [30, 10]; - const width = cfg.size[0], - height = cfg.size[1]; +// const width = cfg.size[0], +// height = cfg.size[1]; - const wrapperRect = group.addShape('rect', { - attrs: { - x: width / 2, - y: height / 2, - width: width, - height: height, - stroke: cfg.style.stroke, - fill: 'transparent' - }, - name: 'wrapper' - }); +// const wrapperRect = group.addShape('rect', { +// attrs: { +// x: width / 2, +// y: height / 2, +// width: width, +// height: height, +// stroke: cfg.style.stroke, +// fill: 'transparent' +// }, +// name: 'wrapper' +// }); - group.addShape('rect', { - attrs: { - x: width / 2, - y: height / 2, - width: width, - height: height / 2, - fill: cfg.style.fill, - stroke: cfg.style.stroke - }, - name: 'top-rect' - }); +// group.addShape('rect', { +// attrs: { +// x: width / 2, +// y: height / 2, +// width: width, +// height: height / 2, +// fill: cfg.style.fill, +// stroke: cfg.style.stroke +// }, +// name: 'top-rect' +// }); - group.addShape('rect', { - attrs: { - x: width / 2, - y: height, - width: width, - height: height / 2, - fill: cfg.style.fill, - stroke: cfg.style.stroke - }, - name: 'bottom-rect' - }); +// group.addShape('rect', { +// attrs: { +// x: width / 2, +// y: height, +// width: width, +// height: height / 2, +// fill: cfg.style.fill, +// stroke: cfg.style.stroke +// }, +// name: 'bottom-rect' +// }); - group.addShape('text', { - attrs: { - x: width, - y: height * (3 / 4), - textAlign: 'center', - textBaseline: 'middle', - text: 'front', - fill: '#000', - fontSize: 16 - }, - name: 'front' - }); +// group.addShape('text', { +// attrs: { +// x: width, +// y: height * (3 / 4), +// textAlign: 'center', +// textBaseline: 'middle', +// text: 'front', +// fill: '#000', +// fontSize: 16 +// }, +// name: 'front' +// }); - group.addShape('text', { - attrs: { - x: width, - y: height * (5 / 4), - textAlign: 'center', - textBaseline: 'middle', - text: 'rear', - fill: '#000', - fontSize: 16 - }, - name: 'rear' - }); +// group.addShape('text', { +// attrs: { +// x: width, +// y: height * (5 / 4), +// textAlign: 'center', +// textBaseline: 'middle', +// text: 'rear', +// fill: '#000', +// fontSize: 16 +// }, +// name: 'rear' +// }); - return wrapperRect; - }, +// return wrapperRect; +// }, - getAnchorPoints() { - return [ - [1, 0.25], - [1, 0.75] - ]; - } -}); +// getAnchorPoints() { +// return [ +// [1, 0.25], +// [1, 0.75] +// ]; +// } +// }); class LinkQueue extends Engine { + defineOptions() { return { element: { head: { - type: 'link-Queue-head', - label: '[id]', - size: [60, 80], + type: 'rect', + label: '[label]', + size: [60, 40], style: { stroke: '#333', fill: '#b83b5e' @@ -106,9 +107,9 @@ G6.registerNode('link-Queue-head', { }, link: { front: { - type: 'line', - sourceAnchor: 0, - targetAnchor: 0, + type: 'polyline', + sourceAnchor: 1, + targetAnchor: 5, style: { stroke: '#333', endArrow: { @@ -120,7 +121,7 @@ G6.registerNode('link-Queue-head', { rear: { type: 'polyline', sourceAnchor: 1, - targetAnchor: 3, + targetAnchor: 5, style: { stroke: '#333', endArrow: { @@ -157,10 +158,16 @@ G6.registerNode('link-Queue-head', { layout: { xInterval: 50, yInterval: 50 + }, + interaction: { + dragNode: ['node'] } }; } + sourcesPreprocess(sources) { + sources.head[1].external = null; + } /** * 对子树进行递归布局 @@ -186,51 +193,56 @@ G6.registerNode('link-Queue-head', { layout(elements, layoutOptions) { - let head = elements.head[0]; + let head1 = elements.head[0], + head2 = elements.head[1], + nodes = elements.node, + headHeight = head1.get('size')[1]; + + let roots = nodes.filter(item => item.root).reverse(); - if(head.front) { - let d = head.get('size')[1] / 2 - head.front.get('size')[1], - x = layoutOptions.xInterval * 2.5, - y = head.front.get('size')[1] / 2 + 1.5 * d; + for(let i = 0; i < roots.length; i++) { + let root = roots[i], + height = root.get('size')[1]; - head.front.set({ x, y }); + root.set('y', root.get('y') + i * (layoutOptions.yInterval + height)); + this.layoutItem(root, null, layoutOptions); } - if(head.front.next) { - this.layoutItem(head.front.next, head.front, layoutOptions); - } + let x = -50, y = roots.length? roots[roots.length - 1].get('y'): 0, + nodeHeight = roots.length? roots[roots.length - 1].get('size')[1]: 0; + + head1.set({ x, y: y + nodeHeight * 3 }); + head2.set({ x, y: head1.get('y') + headHeight }); } } - +const data = { + head: [ + { + "type": "QPtr", + "id": 140737338526359, + "label": "front", + "front": "node#8358681150976310000", + "external": [ + "lq" + ] + }, + { + "type": "QPtr", + "id": 140737338526360, + "label": "rear", + "rear": "node#15844482482171916", + "external": null + } + ], + node: [] +} const LQueue = function(container) { return{ engine: new LinkQueue(container), - data: [{ - head: [{ - type: "QPtr", - id: 44, - front: 'node#1', - rear: 'node#13' - }], - node: [ - { - id: 1, - next: 12, - root: true - }, - { - id: 12, - next: 13 - }, - { - id: 13, - next: null - } - ] - }] + data: [data] } }; diff --git a/demo/dataStruct/linkList.js b/demo/dataStruct/linkList.js index 1fa4959..ac60250 100644 --- a/demo/dataStruct/linkList.js +++ b/demo/dataStruct/linkList.js @@ -13,7 +13,7 @@ class LinkList extends Engine { size: [60, 30], style: { stroke: '#333', - fill: '#b83b5e' + fill: '#eaffd0' } } }, @@ -24,10 +24,7 @@ class LinkList extends Engine { targetAnchor: 0, style: { stroke: '#333', - endArrow: { - path: G6.Arrow.triangle(8, 6, 0), - fill: '#333' - }, + endArrow: 'default', startArrow: { path: G6.Arrow.circle(2, -1), fill: '#333' @@ -41,10 +38,7 @@ class LinkList extends Engine { targetAnchor: 3, style: { stroke: '#333', - endArrow: { - path: G6.Arrow.triangle(6, 6, -2), - fill: '#333' - }, + endArrow: 'default', startArrow: { path: G6.Arrow.circle(2, -1), fill: '#333' @@ -92,7 +86,7 @@ class LinkList extends Engine { layout(elements, layoutOptions) { - let nodes = elements.default, + let nodes = elements, rootNodes = [], node, i; @@ -116,9 +110,9 @@ class LinkList extends Engine { } -const LList = function(container) { +const LList = function(container, options) { return{ - engine: new LinkList(container), + engine: new LinkList(container, options), data: [[ { id: 1, root: true, next: 2, external: ['gg'] }, { id: 2, next: 3 }, @@ -129,15 +123,19 @@ const LList = function(container) { { id: 7, next: 8 }, { id: 8, next: 4 }, { id: 9, root: true, next: 10 }, - { id: 10 } + { id: 10, free: true } ], [ - { id: 1, root: true, next: 2, external: ['gg'] }, + { id: 1, root: true, next: 2 }, { id: 2, next: 3 }, - { id: 3, next: 6 }, - { id: 6, next: 7 }, - { id: 7, next: 8 }, - { id: 8 } + { id: 3, next: 8, external: ['gg'] }, + { id: 8, next: 12 }, + { id: 12, next: 13 }, + { id: 13 } + ], + [ + { id: 1, root: true, next: 2 }, + { id: 2 } ]] } }; diff --git a/demo/demo.html b/demo/demo.html index ae2df7c..1ba2602 100644 --- a/demo/demo.html +++ b/demo/demo.html @@ -14,7 +14,28 @@ .container { width: 100%; - height: 600px; + height: 400px; + background-color: #fafafa; + border: 1px solid #ccc; +} + +.down { + display: flex; + margin-top: 20px; +} + +#freed { + width: 200px; + height: 300px; + border: 1px solid #ccc; + background-color: #fafafa; + margin-right: 30px; +} + +#leak { + width: 400px; + height: 300px; + border: 1px solid #ccc; background-color: #fafafa; } @@ -22,12 +43,19 @@
+ + +