2020软件工程作业05

格式(必做)

为了方便其他学校的老师或者助教了解课程实况,请大家在作业开头添加格式描述:

这个作业属于哪个课程https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/
这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10619
这个作业的目标 学术家族树
作业正文  https://www.cnblogs.com/asdfghjkl456/p/12713132.html
其他参考文献 ...


1.博客链接和Github项目链接

结对同学的博客链接:

学号 姓名 博客链接
20177725 周伊鑫 https://home.cnblogs.com/u/asdfghjkl456/
20177723 何莹 https://home.cnblogs.com/u/heying1226/

本作业博客链接:https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10619

Github项目地址:

2.具体分工

20177723   何莹:主要负责UI设计、素材收集、归纳总结

20177725周伊鑫:主要负责编写代码、归纳总结、测试

3.PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning 计划  60  60
Estimate 估计这个任务需要多少时间  1840  
Development 开发  240  300
Analysis 需求分析 (包括学习新技术)  240  180
Design Spec 生成设计文档 100   120
Design Review 设计复审 120  80 
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60  60 
Design 具体设计 120  150 
Coding 具体编码 240  150 
Code Review 代码复审 180  120 
Test 测试(自我测试,修改代码,提交修改) 120  120 
Reporting 报告 120  100 
Test Repor 测试报告 60  60 
Size Measurement 计算工作量 90  60 
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 90  60 
合计    1840  1620

 


4.解题思路描述与设计实现说明

4.1解题思路:

分析题目的需求我们可以知道大致的主要实现过程是这样的:首先我们需要在web页面提供一个文本框,然后在文本框中输入给定的师生信息,接着把师生信息以树形结构的形式展现出来。因此可知我们可以初步得到代码的组织与内部实现设计如下图所示:

4.2关键算法及其代码实现:

4.2.1创建支持多行输入的文本框以及点击按钮:

主要代码如下:

<textarea type="textarea" id="text" cols="60" rows="10" class="center" placeholder="请输入内容"></textarea>
<button href="javascript:;" onclick="getdata()" class="button_left">建立家族树</button>

说明:extarea标签用来定义多行的文本输入控件,其中的文本区可以容纳无限数量的文本,可以通过 cols 和 rows 属性来规定 textarea 的尺寸;button标签用来定义一个按钮,在 button 元素的内部,可以放置内容,onclick的属性由元素上的鼠标点击触发;

4.2.2处理文本框中输入的数据:

数据的输入处理考虑的是关键信息的提取。第一,我们要提取出每一个人的身份标签,如导师、2016级博士生、2017级本科生等;第二,我们要提取出导师和学生的名字信息,如张三、天一、吴五等,对输入文本的切分以及关键信息的提取是我们后面正确构造出树形结构的师门树的关键所在。

主要代码如下:

function getdata() {
    var text = $("#text").val();                    //获取id为text的textarea的全部内容
    var text1 = text.split("

");//针对多组数据输入的情况,以“

"为关键字进行分组,调用split函数进行分割
    for (var k = 0; k < text1.length; k++) {           //text1.length用于得到分组的数量
         var arry = text1[k].split("
");    //针对每一组数据,以“
"为关键字进行分组,得到每条导师和学生的信息
         for (var ii = 0; ii < arry.length; ii++) {
             var newarr = arry[ii].split("");//针对每条导师和学生的信息,以“:”为关键字进行分组,可得到身份标签和身份信息
             var a1 = newarr[0];        //获取身份标签,如导师、2016级博士生等,保存在a1变量
             alert(a1);          //alert函数用于在web页面上显示变量的值,当前用于显示身份标签
             var a2 = newarr[1];          //获取身份信息,如天一、王二、吴五等,保存在a2变量
             var a3 = a2.split("");//针对每组身份信息,以“、”为关键字进行切分,得到每个人的名字信息
             for (var j = 0; j < a3.length; j++) {  //a3.length用于得到每条身份信息里名字的数量
             alert(a3[j]);                                 //显示每个导师或学生的名字
                }
            }
        }
    }

说明:首先,我们需要获取文本域中的信息内容,在这里可以利用.val()方法来处理表单元素的值,用它来获取id为text的文本域中的全部内容,并存储在text变量中。接着,就是根据关键字的标志信息来切分文本内容,例如多组师生信息的输入是以“ "为标志来切分成单组的,而身份标签和名字信息是以”:“为标志进行切分,多个名字之间按照”、“标志进行切分,在切分之后,将相应的信息存储到相应的变量中,详细实现过程可以参考上面的代码注释。

4.2.3将处理好的数据以树形结构呈现:

这个算法的实现确实超出了我和队友的能力,我们不仅要将处理好的信息以树形结构的形式组织展现,并且还要实现节点的缩放功能,尽管初步学习了有关前端的一些知识我们还是感到无从入手。最后,在网上查阅了相关的实现方法之后,我们决定利用d3.js库来实现树形结构,d3.js是一个JavaScript库,用于根据数据来处理文档,使用它主要是用来做数据可视化的。有关d3的学习我们参考了d3官网http://d3js.org/和网上的教程http://www.it1352.com/OnLineTutorial/d3js/index.html

主要代码如下:

首先我们需要通过链接的方式导入d3.js文件:

<script src="http://d3js.org/d3.v3.min.js"></script>

以下是生成树形结构和实现节点缩放功能的主要代码:

function maketree(k) {
        var margin = {
                top: 20,
                right: 120,
                bottom: 20,
                left: 120
            },
            width = 960 - margin.right - margin.left,
            height = 500 - margin.top - margin.bottom;
        var i = 0,
            duration = 750, //过渡延迟时间
            root;
        var tree = d3.layout.tree() //创建一个树布局
            .size([height, width]);
        var diagonal = d3.svg.diagonal()
            .projection(function(d) {
                return [d.y, d.x];
            }); //创建新的斜线生成器
        //声明与定义画布属性
        var svg = d3.select("body").append("svg")
            .attr("width", width + margin.right + margin.left)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
        root = treeData[k]; //treeData为上边定义的节点属性
        root.x0 = height / 2;
        root.y0 = 0;
        update(root);
        function update(source) {
            // Compute the new tree layout.计算新树图的布局
            var nodes = tree.nodes(root).reverse(),
                links = tree.links(nodes);
            // Normalize for fixed-depth.设置y坐标点,每层占180px
            nodes.forEach(function(d) {
                d.y = d.depth * 180;
            });
            // Update the nodes…每个node对应一个group
            var node = svg.selectAll("g.node")
                .data(nodes, function(d) {
                    return d.id || (d.id = ++i);
                }); //data():绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定
            // Enter any new nodes at the parent's previous position.新增节点数据集,设置位置
            var nodeEnter = node.enter().append("g") //在 svg 中添加一个g,g是 svg 中的一个属性,是group的意思,它表示一组什么东西,如一组lines,rects ,circles其实坐标轴就是由这些东西构成的
                .attr("class", "node") //attr设置html属性,style设置css属性
                .attr("transform", function(d) {
                    return "translate(" + source.y0 + "," + source.x0 + ")";
                })
                .on("click", click);
            nodeEnter.append("rect")
                .attr("x", -23)
                .attr("y", -10)
                .attr("width", 70)
                .attr("height", 20)
                .attr("rx", 10)
                .style("fill", "#800000"); //d 代表数据,也就是与某元素绑定的数据。
            nodeEnter.append("text")
                .attr("x", function(d) {
                    return d.children || d._children ? 13 : 13;
                })
                .attr("dy", "10")
                .attr("text-anchor", "middle")
                .text(function(d) {
                    return d.name;
                })
                .style("fill", "white")
                .style("fill-opacity", 1);
            var nodeUpdate = node.transition() //开始一个动画过渡
                .duration(duration) //过渡延迟时间,此处主要设置的是圆圈节点随斜线的过渡延迟
                .attr("transform", function(d) {
                    return "translate(" + d.y + "," + d.x + ")";
                });
            nodeUpdate.select("rect")
                .attr("x", -23)
                .attr("y", -10)
                .attr("width", 70)
                .attr("height", 20)
                .attr("rx", 10)
                .style("fill", "#800000");
            nodeUpdate.select("text")
                .attr("text-anchor", "middle")
                .style("fill-opacity", 1);
            // Transition exiting nodes to the parent's new position.过渡现有的节点到父母的新位置。
            //最后处理消失的数据,添加消失动画
            var nodeExit = node.exit().transition()
                .duration(duration)
                .attr("transform", function(d) {
                    return "translate(" + source.y + "," + source.x + ")";
                })
                .remove();
            nodeExit.select("circle")
                .attr("r", 1e-6);
            nodeExit.select("text")
                .attr("text-anchor", "middle")
                .style("fill-opacity", 1e-6);
            // Update the links…线操作相关
            //再处理连线集合
            var link = svg.selectAll("path.link")
                .data(links, function(d) {
                    return d.target.id;
                });
            // Enter any new links at the parent's previous position.
            //添加新的连线
            link.enter().insert("path", "g")
                .attr("class", "link")
                .attr("d", function(d) {
                    var o = {
                        x: source.x0,
                        y: source.y0
                    };
                    return diagonal({
                        source: o,
                        target: o
                    }); //diagonal - 生成一个二维贝塞尔连接器, 用于节点连接图.
                })
                .attr('marker-end', 'url(#arrow)');
            // Transition links to their new position.将斜线过渡到新的位置
            //保留的连线添加过渡动画
            link.transition()
                .duration(duration)
                .attr("d", diagonal);
            // Transition exiting nodes to the parent's new position.过渡现有的斜线到父母的新位置。
            //消失的连线添加过渡动画
            link.exit().transition()
                .duration(duration)
                .attr("d", function(d) {
                    var o = {
                        x: source.x,
                        y: source.y
                    };
                    return diagonal({
                        source: o,
                        target: o
                    });
                })
                .remove();
            // Stash the old positions for transition.将旧的斜线过渡效果隐藏
            nodes.forEach(function(d) {
                d.x0 = d.x;
                d.y0 = d.y;
            });
        }
        //定义一个将某节点折叠的函数
        // Toggle children on click.切换子节点事件
        function click(d) {
            if (d.children) {
                d._children = d.children;
                d.children = null;
            } else {
                d.children = d._children;
                d._children = null;
            }
            update(d);
        }
    }

5.附加特点设计与展示

5.1设计的创意独到之处,这个设计的意义

1.在网页上我们能够支持多棵树并存的形式,但由于能力有限,暂时还没办法完成关联树的实现;

2.我们在页面文本框的底部添加了一个刷新按钮,考虑到用户可能输错数据或者在实现一组家族树后想要继续输入数据的需求,可以比较快捷地进行更改;

3.我们在页面上插入了一些背景图片来进行美化界面;

5.2实现思路

首先我们需要在web页面提供一个文本框,然后在文本框中输入给定的师生信息,接着把师生信息以树形结构的形式展现出来。

5.3贴出你认为重要的/有价值的代码片段,并解释

实现刷新功能:

<input type=button value=刷新 onclick="location.reload()" class="button_right">

利用css选择器来插入背景图片以及美化字体和文本框:

body {
    margin: 0px;
    padding: 0px;
    background-image: url('images/timg.jpg');
    background-size: 100%;
    background-repeat: repeat;
    background-size: cover;
    text-align: center;
}
p {
    margin: 0;
    padding: 0;
}
.flex-container {
    background-size: 100% 100%;
    background-attachment: fixed;
}
.center {
    display: block;
    margin-left: auto;
    margin-right: auto;
    margin-top: auto;
    margin-bottom: auto;
    opacity: 0.4;
}
.button_left {
    position: absolute;
    left: 410px;
     100px;
    padding: 4px;
    opacity: 0.4;
}
.button_right {
    position: absolute;
    right: 410px;
     100px;
    padding: 5px;
    opacity: 0.4;
}
.node {
    cursor: auto;
}
.node circle {
    fill: rgb(174, 53, 164);
    stroke: rgb(224, 124, 9);
    stroke- 3px;
}
.node rect {
    fill: #800000;
    stroke: #800000;
    stroke- 5px;
}
.node text {
    font: 12px "楷体", sans-serif;
}
.link {
    fill: none;
    stroke: rgb(28, 235, 166);
    stroke- 2px;
}
#title {
    text-align: center;
    color: rgb(73, 26, 245);
    font: 30px "楷体", sans-serif;
    font-weight: normal;
    line-height: 70px;
    text-shadow: rgb(34, 34, 34) 2px 2px 3px;
    background: rgb(243, 111, 49);
}

5.4成果展示

1.初始界面:

2.生成单棵师门树:

文本框输入:

生成的师门树:

3.多棵师门树共存:

文本框输入:

生成的师门树:


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

目录结构:
目录说明:

bootstrap:bootstrap框架文件

css:网页的css样式文件

images:插入的图片

js:html文件中需要导入的一些js文件

type:html中需导入的css文件

学术家族树:html文件

README:目录说明与使用说明文件

使用说明


 7.单元测试

1.测试工具:Mocha

测试工具的学习网站:http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html

2.对输入文本进行数据处理函数的测试:


8.贴出Github的代码签入记录【1'】

  • 请合理记录commit信息

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


 10.评价你的队友

原文地址:https://www.cnblogs.com/asdfghjkl456/p/12713132.html