这个作业属于哪个课程 | 软件工程课程 |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | 学习html css js等知识,完成网页下师门树的构建 |
本人 | 031802534(吴少冰) |
结对队友 | 031802502(陈锦辉) |
结对队友博客 | 队友博客 |
github网站 | 031802534-031802502 |
结对流程
结对分工
-
写在前面
- 由于两人都是对前端知识完全不懂,本次作业过程挺痛苦的,一切知识都要从零开始自学,因此结对的大部分时间都是在各自学习新的知识,由于啥都不太懂,分工也没有分工好,只能大致描述。
-
031802534 吴少冰
- UI设计、需求分析、单元测试、博客撰写。
-
031802502 陈锦辉
- 代码实现、素材收集、博客撰写。
时间流程
- 2020年10月6日,对作业进行讨论和分析,罗列出需要学习的新知识和新技术,决定两人先各自学习对应的基础知识,看学习情况决定更具体分工。
- 2020年10月6日至2020年10月9日,各自学习包括html、css、js等知识。
- 2020年10月9日,决定分工,学习分工任务,分别完成对应任务(基本是边学边做)。
- 2020年10月11日,初步完成博客,讨论交流没有考虑到的问题和优化方法。
- 2020年10月12日,对博客和代码进行进一步的修改和完善。
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 60 | 50 |
Estimate | 估计这个任务需要多少时间 | 60 | 45 |
Development | 开发 | 400 | 600 |
Analysis | 需求分析 (包括学习新技术) | 300 | 200 |
Design Spec | 生成设计文档 | 100 | 60 |
Design Review | 设计复审 | 100 | 100 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 400 | 680 |
Code Review | 代码复审 | 60 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 180 | 150 |
Reporting | 报告 | 120 | 120 |
Test Repor | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 30 | 30 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 2020 | 2315 |
解题思路描述与设计实现说明
解题思路描述
代码实现思路
-
读入和运行:在网页上设计对应的输入框图和运行按键,用户可以将对应数据输入到框图当中,并通过点击运行按键(生成师门树)来进行运行。这一部分内容将通过html的对应设计完成。
-
数据处理(初步构思):对于单一生成树,我们想通过文本读入的数据信息在父节点和子节点之间的边上显示关系来作为连接依据,将某个人所在的公司等信息作为文本信息补充在每个节点点击后生成的框内。对于互联树,我们本想将每个节点通过相同的逻辑线,将多棵树进行合并成一棵更大的树,但在真正代码编写过程中,由于知识的缺漏等等原因,没有完成个人所在公司等信息的保存和互联树功能的实现。
-
树形生成:本来是队伍两人一起在研究如何做这一块,但因为太菜了没研究出来,后经过网上查找和讨论,发现有一些库可以用来直接生成树,在经过讨论后,决定选用调用相对简单的js的d3库进行生成树。
流程图与数据流图
-
流程图
-
数据流图(尽力画了,感觉好像有问题。。。。)
有价值的代码片段及解释
- 创建支持多行输入的文本框以及点击按钮:
主要代码如下:
<textarea type="textarea" id="text" cols="60" rows="10" class="center" placeholder="请输入内容"></textarea>
<button href="javascript:;" onclick="getdata()" class="button_left">建立师门jiuxiaoyunw树</button>
- 处理文本框中输入的数据:
数据的输入处理考虑的是关键信息的提取。第一,我们要提取出每一个人的身份标签,如导师、2016级博士生、2017级本科生等;第二,我们要提
取出导师和学生的名字信息,如张三、天一、吴五等,对输入文本的切分以及关键信息的提取是我们后面正确构造出树形结构的师门树的关键所在。
主要代码如下:
function getdata() {
var text = $("#text").val(); //获取id为text的textarea的全部内容
var text1 = text.split("\n\n");//针对多组数据输入的情况,以“\n\n"为关键字进行分组,调用split函数进行分割
for (var k = 0; k < text1.length; k++) { //text1.length用于得到分组的数量
var arry = text1[k].split("\n"); //针对每一组数据,以“\n"为关键字进行分组,得到每条导师和学生的信息
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变量中。接着,就是根据关键字的标志信息来切分文本内容,例如多组师生信息的输入是以“\n\n"为标志来切分成单组的,而身份标签和名字信息是以”:“为标志进行切分,多个名字之间按照”、“标志进行切分,在切分之后,将相应的信息存储到相应的变量中,详细实现过程可以参考上面的代码注释。
- 将处理好的数据以树形结构呈现:
这个算法的实现确实超出了我和队友的能力,我们不仅要将处理好的信息以树形结构的形式组织展现,并且还要实现节点的缩放功能,尽管初步学习了有关前端的一些知识我们还是感到无从入手。最后,在网上查阅了相关的实现方法之后,我们决定利用d3.js库来实现树形结构,d3.js是一个JavaScript库,用于根据数据来处理文档,使用它主要是用来做数据可视化的。有关d3的学习我们参考了d3官网http://d3js.org/和网上的教程http://www.it1352.com/OnLineTutorial/d3js/index.html
主要代码如下:
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);
}
}
附加特点设计与展示
设计的创意独到之处,这个设计的意义
- 由于实在是太菜了,具体要求都有些没有完成,特点展示也基本算不上,唯一一个能说的就是添加了刷新按钮,可以直接在首页面进行数据的重复读入和更替,也便于用户更新数据读入。
实现思路
- 学习和调用d3库的相关操作进行代码实现
重要的/有价值的代码片段
<input type=button value=刷新 onclick="location.reload()" class="button_right">
成果展示
- 首页面: 带有数据读入框,生成树按键以及刷新按键,在读入框中输入对应数据,点击生成树按键即可。
- 单棵树界面以及缩放:单颗树生成后效果如图,可以通过点击对应节点对其进行缩放和展开,可以通过鼠标进行拖放和放大缩小。
- 多棵树并存:多棵树数据输入后点击生成,可以通过鼠标的拖拉和放大缩小来查看所有树。
目录说明与使用方法
目录说明:
- 师门树
- bootstrap:bootstrap框架文件
- css:网页的css样式文件
- images:插入的图片
- js:html文件中需要导入的一些js文件
- type:html中需导入的css文件
- 师门树:html文件
- README:目录说明与使用说明文件
使用说明:
- 点击github上的“Clone or download”按钮后,将上述文件打包下载,解压后即可使用,需保证上述所有文件在同一个文件夹下。
- 使用时直接用Chrome打开师门树.html文件即可,输入格式按照作业要求即可。
- 在出现的文本框输入数据,点击生成师门树按钮,将会在下方生成一棵以导师为根节点的树,然后点击刷新按钮可以刷新页面重新输入。
单元测试
测试工具与学习方法
- 通过网上查询等方面,选择vue-jest作为测试工具。
- 通过网上的相关博客文档等内容进行学习。
单元测试展示
情况考虑
- 对可能出现情况进行枚举,生成对应数据。
- 与舍友和队友等寻求不同思考,考虑是否有遗漏什么情况。
- 设身处地放在测试人员的角度进行思考,并邀请认识的人进行思路汇总。
github展示
遇到的代码模块异常或结对困难及解决方法
-
单元测试
-
我的主要任务是对整体的原型分析和单元测试等,最麻烦的部分是单元测试怎么使用,因为自己对这一方面根本不了解,只有在之前那次作业中有所学习,但学习的内容完全不足,所以在单元测试上卡了非常久的时间。
-
通过自己在网上的查询和学习后,对单元测试有了一定的了解,但还是没有能完成任务,后请教了自己实验室的学长,从他那里学习到了很多关于单元测试的东西,对应单元测试的代码很多也是他教我的,非常感谢能有这样一位学长!
-
-
时间安排
- 由于这段时间正好是我所参与的实验室训练安排比较紧凑的时间,导致我没有太多的时间用于学习更多关于网页创建的知识,代码编写的繁重工作基本都是落在我队友身上,我也仅仅只能与他进行一定的讨论和探讨,并用剩余时间完成自己的任务,也正因如此,本次作业的完成程度不是很理想,挺对不起我的队友的。
评价队友
- 非常认真和努力的一位同学,他跟我一样都是对网页前端等等这些知识完全不知的,都是靠着自己学习来完成代码。特别是代码编写这一繁重任务基本都是交给他来完成的,非常感谢他。不过缺点还是有的,比如工作开始的时候没有正确预估好自己的完成时间和想要完成的功能等等,导致工作进程不够较慢。希望能够共同进步,学习更多知识。