2020软件工程结对编程之实验室程序实现

结对成员

这个作业属于哪个课程
https://edu.cnblogs.com/campus/fzu/SE2020/
这个作业要求在哪里
https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277
这个作业的目标 在网页页面上呈现树形结构形式的师门树,树的节点,鼠标点击后是可以缩放的。同时,支持呈现多棵树并存、两棵关联树共存等形式。
学号 031802339、031802323

Github项目地址:

Github项目地址:https://github.com/zhengguorong339/031802323-031802339

结对同学博客链接

学号 姓名 博客链接
031802323 彭宇泽 https://www.cnblogs.com/AshCeimpeng/p/13799978.html
031802339 郑国荣 https://www.cnblogs.com/double-points/p/13776022.html

具体分工

031802339郑国荣:主要负责UI设计、素材收集、归纳总结
031802323彭宇泽:主要负责编写代码、归纳总结、测试

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(小时) 实际耗时(小时)
Planning 计划 1 0.5
Estimate 估计这个任务需要多少时间 0.5 0.5
Develop 开发 5 8
Analysis 需求分析 (包括学习新技术) 30 35
Design Spec 生成设计文档 2 2
Design Review 设计复审 2 2
Coding Standard 代码规范(为目前的开发制定合适的规范) 1 2
Design 具体设计 3 3
Coding 具体编码 20 25
Code Review 代码复审 1 1
Test 测试(自我测试、修改代码、提交修改) 5 5
Reporting 报告 2 3
Test Repor 测试报告 1.5 2
Size Measurement 计算工作量 0.5 0.5
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 2 2
合计 77.5 91.5

解题思路描述

需求分析:首先我们需要在web页面提供一个文本框,然后在文本框中输入给定的师生信息,接着把师生信息以树形结构的形式展现出来。因此信息的读入输出流程如下图所示:

关键算法及其代码实现

主要代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>T  R  E  E</title>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <style>
        .button {
            background-color: #4CAF50; /* Green */
            border: none;
            color: white;
            padding: 10px 20px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 12px;
            margin: 4px 2px;
            -webkit-transition-duration: 0.4s; /* Safari */
            transition-duration: 0.4s;
            cursor: pointer;
        }

        .button1 {
            background-color: white;
            color: black;
            border: 2px solid #4CAF50;
        }

            .button1:hover {
                background-color: #4CAF50;
                color: white;
            }

        .text {
            border-style: solid;
            border-color: #98bf21;
        }
    </style>
</head>
<body>
    <div id="txt" align="center">
        <h1>Create A Tree</h1>
        <textarea id="input" class="text" cols="60" rows="10" placeholder="请输入内容"></textarea>
    </div>

    <div id="but" align="center" style="vertical-align: middle;">
        <input type=button value=刷新 onclick="location.reload()" class="button button1" style="margin-right:150px;">
        <button class="button button1" onclick="jiexi()" style="margin-left:150px;">生成</button>
    </div>
    <div id="main">
        <div id="Tree"></div>
    </div>
    <script>
        function jiexi() {
            var text = document.getElementById("input").value;
            var top = text.slice(text.indexOf(":") + 1, text.indexOf("2"))
            var cnt = text.match(/2/g);
            var line = text.match(/:/g).length;
            var lines = text.split(/[(\r\n)\r\n]+/)
            var start = 0, branch = 0, end = 0;
            for (var i = 0; i < line; i++) {
                if (lines[i].indexOf("导师") != -1) {
                    start = i;
                    i = i + 1;
                    branch = 0;
                    for (var j = i; j < line; j++) {
                        if (lines[j].indexOf("生:") != -1) {
                            branch = branch + 1;
                        }
                        if (lines[j].indexOf("导师") != -1) {
                            end = j - 1;
                            showAtree(start, branch, end, lines);
                            break;
                        }
                        if (j == line - 1) {
                            end = j;
                            showAtree(start, branch, end, lines);
                            break;
                        }
                    }
                }
            }
        }
        
        function showAtree(start = 0, branch = 4, end = 5, lines) {
            var flag = true;
            if (flag == 1) {
                let data = {
                    "name": "",
                    "children":
                        [
                            {
                                "name": "",
                                "children":
                                    [
                                        {
                                            "name": "",
                                            "children":
                                                [
                                                ]
                                        }
                                    ]
                            }
                        ]
                };

                data.name = lines[start].slice(lines[start].indexOf(":") + 1, lines[start + 1].indexOf(":"));
                var j = 0;
                for (var i = start; i < start + branch; i++) {
                    data.children[j] = {
                        "name": "",
                        "children":
                            [
                                {
                                    "name": "",
                                    "children":
                                        [
                                        ]
                                }
                            ]
                    };
                    data.children[j].name = lines[i + 1].slice(0, lines[i + 1].indexOf(":"));
                    for (var k = 0; k < lines[i + 1].slice(lines[i + 1].indexOf(":") + 1, 50).split('、').length; k++) {
                        var nam = lines[i + 1].slice(lines[i + 1].indexOf(":") + 1, 50).split('、')[k];
                        data.children[j].children[k] = {
                            "name": "",
                            "children":
                                [
                                ]
                        };
                        data.children[j].children[k].name = nam;
                        var x = -1;
                        var sea = nam + ":"
                        for (var l = start; l < end; l++) {
                            if (lines[l].indexOf(sea) != -1) {
                                x = 1;
                                break;
                            }
                        }
                        if (x == 1) {
                            for (var r = 0; r < lines[l].slice(lines[l].indexOf(":") + 1, 50).split('、').length; r++) {
                                var skill = lines[l].slice(lines[l].indexOf(":") + 1, 50).split('、')[r];
                                data.children[j].children[k].children[r] = [{ "name": "" }];
                                data.children[j].children[k].children[r].name = skill;
                            }
                        }
                    }
                    j = j + 1;
                }

                const root = d3.hierarchy(data);


                root.x0 = dy / 2;
                root.y0 = 0;
                root.descendants().forEach((d, i) => {
                    d.id = i;
                    d._children = d.children;
                });


                var svg = d3.select("#Tree")
                    .append("svg")
                    .attr("width", width)
                    .attr("viewBox", [-margin.left, -margin.top, width, dx])
                    .style("font", "15px sans-serif")
                    .style("user-select", "none");


                const gLink = svg.append("g")
                    .attr("fill", "none")
                    .attr("stroke", "#555")
                    .attr("stroke-opacity", 0.4)
                    .attr("stroke-width", 1.5);


                const gNode = svg.append("g")
                    .attr("cursor", "pointer")
                    .attr("pointer-events", "all");


                function update(source) {
                    const duration = d3.event && d3.event.altKey ? 2500 : 250;
                    const nodes = root.descendants().reverse();
                    const links = root.links();


                    tree(root);

                    var left = root;
                    var right = root;
                    root.eachBefore(node => {
                        if (node.x < left.x) left = node;
                        if (node.x > right.x) right = node;
                    });


                    const height = right.x - left.x + margin.top + margin.bottom;


                    const transition = svg.transition()
                        .duration(duration)
                        .attr("viewBox", [-margin.left, left.x - margin.top, width, height])
                        .tween("resize", window.ResizeObserver ? null : () => () => svg.dispatch("toggle"));


                    const node = gNode.selectAll("g")
                        .data(nodes, d => d.id);


                    const nodeEnter = node.enter().append("g")
                        .attr("transform", d => `translate(${source.y0},${source.x0})`)
                        .attr("fill-opacity", 0)
                        .attr("stroke-opacity", 0)
                        .on("click", d => {
                            d.children = d.children ? null : d._children;
                            update(d);
                        });


                    nodeEnter.append("circle")
                        .attr("r", 6)
                        .attr("fill", d => d._children ? "#ccc" : "#fff")
                        .attr("stroke", 'steelblue')
                        .attr("stroke-width", 2);


                    nodeEnter.append("text")
                        .attr("dy", "0.31em")
                        .attr("x", d => d._children ? -10 : 10)
                        .attr("text-anchor", d => d._children ? "end" : "start")
                        .text(d => d.data.name)
                        .clone(true).lower()
                        .attr("stroke-linejoin", "round")
                        .attr("stroke-width", 3)
                        .attr("stroke", "white");


                    const nodeUpdate = node.merge(nodeEnter).transition(transition)
                        .attr("transform", d => `translate(${d.y},${d.x})`)
                        .attr("fill-opacity", 1)
                        .attr("stroke-opacity", 1);


                    const nodeExit = node.exit().transition(transition).remove()
                        .attr("transform", d => `translate(${source.y},${source.x})`)
                        .attr("fill-opacity", 0)
                        .attr("stroke-opacity", 0);


                    const link = gLink.selectAll("path")
                        .data(links, d => d.target.id);


                    const linkEnter = link.enter().append("path")
                        .attr("d", d => {
                            const o = { x: source.x0, y: source.y0 };
                            return diagonal({ source: o, target: o });
                        });


                    link.merge(linkEnter).transition(transition)
                        .attr("d", diagonal);


                    link.exit().transition(transition).remove()
                        .attr("d", d => {
                            const o = { x: source.x, y: source.y };
                            return diagonal({ source: o, target: o });
                        });


                    root.eachBefore(d => {
                        d.x0 = d.x;
                        d.y0 = d.y;
                    });
                    flag = false;
                }

                update(root);

                return svg.node();
            }
        }

        margin = ({ top: 100, right: 120, bottom: 10, left: 500 });
        var width = 1800;
        dy = 300;
        dx = 30;

        tree = d3.tree().nodeSize([dx, dy]);
        diagonal = d3.linkHorizontal().x(d => d.y).y(d => d.x);
    </script>
</body>
</html>

实现成果展示

初始界面:



生成单棵师门树:



生成多棵师门树




在博客中给出目录说明和使用说明

目录结构:

目录说明:

  • 家族树
    • 学术家族树:html文件
    • README:目录说明与使用说明文件
  • 使用说明:
    • 点击github上的“Clone or download”按钮后,将上述文件打包下载,解压后即可使用,需保证上述所有文件在同一个文件夹下。
      使用时直接用Chrome打开学术家族树.html文件即可,输入格式按照作业要求即可。
    • 在出现的文本框输入数据,点击生成家族树按钮,将会在下方生成一棵以导师为根节点的树(暂不支持关联树的实现...),然后点击刷新按钮可以刷新页面重新输入。

Github的代码签入记录

遇到的代码模块异常或结对困难及解决方法

(1)问题描述:对于一组师生信息的输入,不知道以什么为关键字为标志信息,一直无法正确进行切分,提取出每组的师生信息
做过哪些尝试:上网百度、询问同学
是否解决:已经解决
收获:提升了自己分析问题和解决问题的能力,并且对JavaScript的认识有了进一步的提高。
(2)问题描述:针对多组师生信息的输入,一直无法正确进行切分,提取出每组的师生信息
做过哪些尝试:上网百度
是否解决:未经解决

队友评价

031802323:我的队友对于作业要求理解很快,思路清晰。同时态度认真,学习新技术也很快,积极的讨论与研究细节让本次作业能够顺利完成,是一个不折不扣的好队友。
031802339:我的队友是一个努力上进、自学能力强的人,这次多亏了他的努力和对我的帮助,才使得我们的结对项目顺利完成。个人觉得我们两个在结对配合和交流上相对比较顺畅,总能适时地交流意见和建议。通过这次结对,从队友身上学到了很多。

posted @ 2020-10-11 22:49  AshCrimpeng  阅读(160)  评论(0编辑  收藏  举报