|
|
@@ -6,6 +6,8 @@
|
|
|
:key="requirement.id"
|
|
|
v-bind="requirement"
|
|
|
:ref="`treenode-${requirement.id}`"
|
|
|
+ @addChild="addChild"
|
|
|
+ @deleteNode="deleteNode"
|
|
|
/>
|
|
|
</div>
|
|
|
<canvas id="line-drawer" :height="HEIGHT" :width="WIDTH"></canvas>
|
|
|
@@ -32,35 +34,53 @@ export default {
|
|
|
parent2children: {},
|
|
|
depth2node: {},
|
|
|
layout: {},
|
|
|
+ ctx: null,
|
|
|
};
|
|
|
},
|
|
|
mounted() {
|
|
|
- for (let i = 0; i < this.data.length; i += 1) {
|
|
|
- const parentid = this.data[i].parent;
|
|
|
- if (!Object.prototype.hasOwnProperty.call(this.parent2children, parentid)) {
|
|
|
- this.parent2children[parentid] = [];
|
|
|
- }
|
|
|
- this.parent2children[parentid].push(this.data[i]);
|
|
|
- }
|
|
|
- let depth = 1;
|
|
|
- let parentList = [null];
|
|
|
- for (;depth < 5; depth += 1) {
|
|
|
+ this.initCanvasCtx();
|
|
|
+ this.regenerateTree();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ initCanvasCtx() {
|
|
|
+ this.ctx = document.getElementById('line-drawer').getContext('2d');
|
|
|
+
|
|
|
+ this.ctx.lineWidth = 1;
|
|
|
+ this.ctx.strokeStyle = '#bbbbbb';
|
|
|
+ },
|
|
|
+ regenerateTree() {
|
|
|
+ this.initParent2Children();
|
|
|
+ this.initDepth2Node();
|
|
|
+ this.calculateLayout();
|
|
|
+ this.locateAndDraw();
|
|
|
+ },
|
|
|
+ initParent2Children() {
|
|
|
+ this.parent2children = {};
|
|
|
for (let i = 0; i < this.data.length; i += 1) {
|
|
|
- if (parentList.includes(this.data[i].parent)) {
|
|
|
- if (!Object.prototype.hasOwnProperty.call(this.depth2node, depth)) {
|
|
|
- this.depth2node[depth] = [];
|
|
|
+ const parentid = this.data[i].parent;
|
|
|
+ if (!Object.prototype.hasOwnProperty.call(this.parent2children, parentid)) {
|
|
|
+ this.parent2children[parentid] = [];
|
|
|
+ }
|
|
|
+ this.parent2children[parentid].push(this.data[i]);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ initDepth2Node() {
|
|
|
+ this.depth2node = {};
|
|
|
+ let depth = 1;
|
|
|
+ let parentList = [null];
|
|
|
+ for (;depth < 5; depth += 1) {
|
|
|
+ this.depth2node[depth] = [];
|
|
|
+ for (let i = 0; i < this.data.length; i += 1) {
|
|
|
+ if (parentList.includes(this.data[i].parent)) {
|
|
|
+ this.depth2node[depth].push(this.data[i]);
|
|
|
}
|
|
|
- this.depth2node[depth].push(this.data[i]);
|
|
|
}
|
|
|
+ parentList = this.depth2node[depth].map((node) => node.id);
|
|
|
}
|
|
|
- parentList = this.depth2node[depth].map((node) => node.id);
|
|
|
- }
|
|
|
-
|
|
|
- this.calculateLayout();
|
|
|
- this.locateAndDraw();
|
|
|
- },
|
|
|
- methods: {
|
|
|
+ },
|
|
|
calculateLayout() {
|
|
|
+ // clear the layout
|
|
|
+ this.layout = {};
|
|
|
const MARGIN_TOP = 40;
|
|
|
const MARGIN_LEFT = 100;
|
|
|
const COL_WIDTH = (WIDTH - MARGIN_LEFT) / 4;
|
|
|
@@ -102,13 +122,10 @@ export default {
|
|
|
const { x, y } = this.layout[id];
|
|
|
this.$refs[`treenode-${id}`].setTreeNodeOffset(x, y);
|
|
|
}
|
|
|
- // 在canvas上绘制节点间连线
|
|
|
- const ctx = document.getElementById('line-drawer').getContext('2d');
|
|
|
- ctx.clearRect(0, 0, WIDTH, HEIGHT);
|
|
|
-
|
|
|
- ctx.lineWidth = 1;
|
|
|
- ctx.strokeStyle = '#bbbbbb';
|
|
|
+ // clear the canvas
|
|
|
+ this.ctx.clearRect(0, 0, WIDTH, HEIGHT);
|
|
|
|
|
|
+ // 在canvas上绘制节点间连线
|
|
|
const kvs = Object.entries(this.parent2children);
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
for (const [parent, children] of kvs) {
|
|
|
@@ -132,12 +149,25 @@ export default {
|
|
|
x: endX,
|
|
|
y: endY + endH / 2,
|
|
|
};
|
|
|
- ctx.moveTo(start.x, start.y);
|
|
|
- ctx.lineTo(end.x, end.y);
|
|
|
- ctx.stroke();
|
|
|
+ this.ctx.beginPath();
|
|
|
+ this.ctx.moveTo(start.x, start.y);
|
|
|
+ this.ctx.lineTo(end.x, end.y);
|
|
|
+ this.ctx.stroke();
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
+ addChild(id) {
|
|
|
+ this.$emit('change', {
|
|
|
+ type: 'addChild',
|
|
|
+ id,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deleteNode(id) {
|
|
|
+ this.$emit('change', {
|
|
|
+ type: 'deleteNode',
|
|
|
+ id,
|
|
|
+ });
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|