2020福州大学软件工程实践结对编程作业二

这个作业属于哪个课程 福州大学软件工程
这个作业要求在哪里 结对编程作业二要求
这个作业的目标 熟练使用github以及了解web页面的编码与设计
学号 031802538 031802520

一、结对信息

团队成员

成员姓名 成员学号 博客地址
林鸿 031802520 我的博客
余立 031802538 队友博客

github仓库地址

FZUli/031802538-031802520

二、具体分工

  • 在初期,双方一同查阅相关资料,了解需要学习的知识内容和其应用方式,讨论明确分工
  • 余立:主要负责HTML+CSS代码编写设置网页的样式同时了解部分Javascript来设计家族树的样式,同时编写博客
  • 林鸿:主要负责学习Javascript代码来进行家族树的框架构建,处理作业中的如鼠标缩放等操作,复审网页样式
  • 在截止前,双方一同讨论如何进行有效的单元测试,搜索相关资料,并初步尝试

三、PSP表格

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

四、解题思路描述与设计实现说明

解题思路

1、首先通过搜索资料了解html+css的设计方式,构建相应的web页面

2、设计好html中的文本框输入数据给js代码处理,以及相应按钮功能

3、编写核心js代码,通过split函数与关键字分割文本数据,分组存储

4、原定以\n\n分割,但由于技能树和工作历程的双换行,再结合学术家族树必有导师,定以导师分割

5、根据相应的符号关键字处理数据,构造相应的家族树模型

6、分函数模块化处理树,设计点击效果以及树的动态更新

7、审查相应的功能同时美化树的样式

流程图

代码解释

  • 数据结构的初始定义
        var treeData = [{
            "name": "",
            "parent": "",
            "children": [{
                "name": "",
                "parent": "",
                "children": [{
                    "name": "",
                    "parent": ""
                }, {
                    "name": "",
                    "parent": "",
                    "children": [{
                        "name": "",
                        parent: ""
                    }]
                }, {
                    "name": "",
                    "parent": ""
                }, {
                    "name": "",
                    "parent": ""
                }]
            }, {
                "name": "",
                "parent": "",
                "children": [{
                    "name": "",
                    "parent": ""
                }, {
                    "name": "",
                    "parent": ""
                }, ]

            }, {
                "name": "",
                "parent": ""
            }, ]
        }];
  • 对于文本框中输入数据,先以“导师:”分割处理成块, 再对块中数据以“\n”处理成树
        function getdata() {
            var text = $("#text").val(); //获取id为text的textarea的全部内容
            var text1 = text.split("导师:");//针对多组数据输入的情况,以"导师:"为关键字进行分组,调用split函数进行分割
            for (var k = 1; k < text1.length; k++) { //text1.length用于得到分组的数量
                var arry = text1[k].split("\n");//针对每一组数据,以“\n"为关键字进行分组,得到每条导师和学生的信息
                var teacher = {
                        name: '',
                        children: []
                    }
                teacher.name=arry[0];
                var w=0;
                for (var ii = 1; ii < arry.length; ii++) {
                    if(arry[ii].length<3) continue;
                    var newarr = arry[ii].split(":");//以“:”为关键字进行分组,可得到身份标签和身份信息
                    var type = [];
                    var type1 = [];
                    var a1 = newarr[0]; //获取身份标签,保存在a1
                    type1.name = a1;
                    var a2 = newarr[1];//获取身份信息,保存在a2
                    var a3 = a2.split("、");//针对每组身份信息,以“、”为关键字进行切分,得到每个人的名字信息
                    w++;
                    for (var j = 0; j < a3.length; j++) { //a3.length用于得到每条身份信息里名字的数量
                        var student = {
                        name: '',
                        children: []
                        }
                        student.name = a3[j];
                        type.push(student);
                    }
                        if(a1.length<=3){ //如果这一行开头是姓名
                            for(var fff=0;fff<teacher.children.length;fff++){
                                for(var fc=0;fc<teacher.children[fff].children.length;fc++){
                                    if(teacher.children[fff].children[fc].name==a1){//根据a1查找树中匹配的姓名
                                        for (var j = 0; j < a3.length; j++)
                                        teacher.children[fff].children[fc].children.push(type[j]);//找到后在其后添加信息
                                    }
                                }
                            }
                            continue;
                        }
                        type1.children = type;
                        teacher.children.push(type1);
                }
                treeData[k] = [];
                treeData[k] = teacher;
                maketree(k,w);
            }
        }
  • 对于已经处理好的数据树,进行遍历,处理出一颗师门树,同时设计好点击的动态缩放效果
function maketree(k,w) {
            var margin = {
                    top: 20,
                    right: 120,
                    bottom: 20,
                    left: 220,
                },
                width = 1200- margin.right - margin.left ;
                height = w*200 ;

            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,w);

            function update(source,w) {
                // 计算新树图的布局
                var nodes = tree.nodes(root).reverse(),
                    links = tree.links(nodes);

                // 设置y坐标点,每层占180px
                nodes.forEach(function(d) {
                    d.y = d.depth * 250;
                });

                // 每个node对应一个group
                var node = svg.selectAll("g.node")
                    .data(nodes, function(d) {
                        return d.id || (d.id = ++i);
                    }); //data():绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定

                // 新增节点数据集,设置位置
                var nodeEnter = node.enter().append("g")
                    .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", "#6AAFD1"); //d 代表数据,也就是与某元素绑定的数据。

                nodeEnter.append("text")
                    .attr("x", function(d) {
                        return d.children || d._children ? 13 : 13;
                    })
                    .attr("dy", "5")
                    .attr("text-anchor", "middle")
                    .text(function(d) {
                        return d.name;
                    })
                    .style("fill", "white")
                    .style("fill-opacity", 1);
                // 将节点过渡到一个新的位置-----主要是针对节点过渡过程中的过渡效果
                //node就是保留的数据集,为原来数据的图形添加过渡动画。首先是整个组的位置
                var nodeUpdate = node.transition() //开始一个动画过渡
                    .duration(duration) //过渡延迟时间,此处主要设置的是圆圈节点随斜线的过渡延迟
                    .attr("transform", function(d) {
                        return "translate(" + d.y + "," + d.x + ")";
                    });
                nodeUpdate.select("rect")
                    .attr("x", -46)
                    .attr("y", -16)
                    .attr("width", 120)
                    .attr("height", 30)
                    .attr("rx", 10)
                    .style("fill", "#6AAFD1");

                nodeUpdate.select("text")
                    .attr("text-anchor", "middle")
                    .style("fill-opacity", 1);

                // 过渡现有的节点到父母的新位置。
                //最后处理消失的数据,添加消失动画
                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);

                // 线操作相关
                //再处理连线集合
                var link = svg.selectAll("path.link")
                    .data(links, function(d) {
                        return d.target.id;
                    });

                //添加新的连线
                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)');

                // 将斜线过渡到新的位置
                //保留的连线添加过渡动画
                link.transition()
                    .duration(duration)
                    .attr("d", diagonal);

                // 过渡现有的斜线到父母的新位置。
                //消失的连线添加过渡动画
                link.exit().transition()
                    .duration(duration)
                    .attr("d", function(d) {
                        var o = {
                            x: source.x,
                            y: source.y
                        };
                        return diagonal({
                            source: o,
                            target: o
                        });
                    })
                    .remove();

                // 将旧的斜线过渡效果隐藏
                nodes.forEach(function(d) {
                    d.x0 = d.x;
                    d.y0 = d.y;
                });
            }

            //定义一个将某节点折叠的函数
            // 切换子节点事件
            function click(d) {
                if (d.children) {
                    d._children = d.children;
                    d.children = null;
                } else {
                    d.children = d._children;
                    d._children = null;
                }
                update(d);
            }
        }

具体效果

  • 根据输入要求的示例输出,静态展示

goodtree

  • 根据点击缩放要求,动态展示

gif

五、附加特点设计与展示

  • 界面背景美化,色调统一
    1、覆盖一张纯蓝色的风景图,没有过多要素,简洁雅观
    2、为了师门树更好地显示,将背景图虚化
    3、给html中body样式添加居中效果,所有div居中显示
    4、添加outline:none语句删除了html中点击后生成的黑框,让界面更优美,以下为原先点击效果
    1 2
    5、添加符合主题的小树图标,美化界面

all

部分CSS样式代码

body {
    margin: 0px;
    padding: 0px;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    font-family: "Microsoft YaHei";
}
.bg{
	background: url('img/background.jpg');
    background-size: cover;
    position: fixed;
    top: -20px;
    left: -20px;
    right: -20px;
    bottom: -20px;
    -webkit-filter: blur(5px);
            filter: blur(5px);
    z-index: -1;
}
.mask {
  width: 100px;
  height: 100px;
  margin-top:15px;
  background-image: url('img/tree.png');
  background-size: cover;
  border-radius: 15px;
}
.button {
    background-color:rgb(126, 214, 248);
    color:#ffffff;
    float:left;
    width: 120px;
    padding: 6px;
    border-radius: 20px;
    font-size: 18px;
    outline:none;
}
  • 增加重置功能按钮
    由于web页面生成原因,如果在生成家族树后再次生成,树将生成在原树下面。为此,添加重置功能按钮清除旧的家族树
<button class="button2" value=重置 onclick="location.reload()">重置</button>
  • 根据节点数量动态设置学术家族树的高度设置,避免因数据过多造成的重叠
    dp
    pic

六、目录说明和使用说明

git

目录说明

  • img文件夹存放相关图标和背景图
  • js文件夹存放下载的js函数库,以便调用
  • style文件即web页面的样式设计,由html文件调用
  • tree文件即最终的web文件,调用以上内容

使用说明

1、在github上下载(code→Download ZIP)至电脑并解压成文件夹
2、在解压出的文件夹中找到tree.html,右键点击打开方式选择Google Chrome打开
3、在输入框中输入相应的测试数据,如:
导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四

刘六:JAVA、数学建模

李二:字节跳动、京东云

4、本次作业中默认多颗树并存,新树生成于旧树之下,若清空请点击重置

七、单元测试

1.测试工具:Mocha

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

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

八、Github的代码签入记录截图

g1
g2

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

1、

  • 问题:在对技能树或项目经历进行名字匹配以及添加节点出现了问题
  • 尝试:调试代码时没有报错,但是生成学术家族树按键按下去没反应,在循环里加了个alert("XX”)进行debug
  • 解决:实质上是在最初的html中尚未添加link语句调用库
  • 收获:多种语言应相互协调,不单向处理

2、

  • 问题:对于没有技能树和功项目经历时按照“\n\n"进行分割可行,添加上就得换个关键字处理
  • 尝试:根据就用输入要求思考如何处理
  • 解决:选择“导师:”进行分割,必然处理出相应的根节点
  • 收获:在最初编写代码时应想好如何处理,而不是在后期调整

3、

  • 问题:对于HTML+CSS部分页面设计的浮动状态运用混乱,设计难以调整
  • 尝试:在慕课网进行系统的学习,了解其使用
  • 解决:通过在css中配置相应的参数调整位置
  • 收获:更加深入了解CSS的处理

4、

  • Javascript对于中英文符号处理有差别,要认真处理

十、评价你的队友

余立

值得学习的地方:

  • 善于运用互联网资料,在博客园、CSDN查找大量相关资料
  • 自学经验丰富,提供多个学习平台网站
  • 对于工作任务处理细致,考虑周到,规划合理

需要改进的地方:

  • 对工作没有积极性,时常拖延
  • 交流讨论时,时常转向生活话题

林鸿

值得学习的地方:

  • 学习效率高,能快速了解代码内容
  • 工作心态良好,稳扎稳打

需要改进的地方:

  • 只有分配工作后快速完成,不会自行规划
  • 不善于查找资料,缺乏自主性
posted @ 2020-10-12 13:51  FZU_LH  阅读(102)  评论(0编辑  收藏  举报