学术家族树的前端实现

这初始的黄金之风luxiaoye

What does not kill me makes me stronger

链接

github地址:https://github.com/O-VIGIA/031702414-031702444.git

结对同学:031702444李尚佳

具体分工

031702414陆志阳:算法设计和实现,单元测试,代码优化

031702444李尚佳:前端页面设计和实现

共同完成:jstree的实现 博客内容撰写

PSP表格

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

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

读完题目,分析要点如下:

  1. 文本数据的提取
  2. 文本数去提取完如何保存和传送
  3. 树状动态结构的生成
  4. 树状结构缩放的实现

代码组织与内部实现设计(类图)

学术家族树的前端实现_第1张图片

说明算法的关键与关键实现部分流程图

在没开始之前 我们两个 是这么想的 ((( :

算法:

缩放算法:

定义 检查函数(节点)

{

​ 检查该节点所有的父节点

​ 如果 其所有父节点的缩放标志全为1,该节点与所有的父节点连线消失并且该节点消失

​ 如果 其至少有一个父节点的缩放标志不为1,该节点只与缩放标志为1的父节点连线消失并且该节点不消失

}

定义 缩放函数(节点)

{

​ 点击节点,以此节点为父节点,找到他的所有的儿子节点(第一层儿子节点),该节点缩放标志为1。

​ 检查节点(子节点)

​ 缩放函数(子节点)

}

主函数()

{

​ 缩放函数(点击的节点);

}

学术家族树的前端实现_第2张图片

在分工开始了之后我是这么想的

算法

。。。。。。。。。。。。。。

最后是则个样子?!

学术家族树的前端实现_第3张图片

多行不E必自闭 ~

好了正经起来:

在打关联树的时候

比较有意思的一个算法可能就是递归查找子节点了,就是当前树的根节点和前面树的节点是否有关联

写这个算法的过程中,因为数据是json格式,所以求父节点下一级子节点的长度就是关键。

刚开始憨憨写了个 json. length()/.size()...发现都不对,最后只能自己去手打,发现手打也没那么难

 //自定义json长度查找函数,返回json树的下层子节点的长度(个数)

​        function getJsonLength(jsonData) {

​            var json_length = 0;

​            for (var temp in jsonData) {

​                //alert("Son is " + item);

​                json_length++;

​            }

​            return jsonLength;

​        }

剩下的就交给我的递归查找函数了,直接上代码,看注释

         /*
​        检查函数,遍历之前所有树的所有子节点,查找是否有导师的学生也是导师的情况,若有此种情况则此树重构 
​        */

​        //@nodes 源json树

​        //@find_name 要找的导师名

​        //@may_need 可能需要添加的json树 

​        function check(nodes, find_name, may_need, keke) {

​            var fanhui1 = 0;

​            var fanhui2 = 1;

​            // alert("checkcheckcheckcheckcheckcheck");

​            var length_now = getJsonLength(nodes.children);

​            // alert("chang = " + length_now)

​            for (var ll = 0; ll < length_now; ll++) {

​                // alert(nodes.children[ll].name);

​                if (nodes.children[ll].name == find_name) {//第ll个子节点的名字是否与要查找的相同

​                    // alert("hhhhhhhhhhhhhh");

​                    quanju_flag = 1;如果有一棵树和其他树有关联此变量为一树的颗数不增加

​                    //add_tree(nodes.children[ll].children, may_need, keke);

​                    // alert("add");

​                    // alert(getJsonLength(may_need));

​                    nodes.children[ll] = may_need;//将该json树添加到儿子节点作为关联

​                    // alert("add success");

​                    return fanhui2;

​                } else {

​                    check(nodes.children[ll], find_name, may_need, keke);

​                    // return;

​                }

​            }

​            return fanhui1;

​        }

其他的地方,也就是搞json的时候的经常犯傻,不过最后还是渐渐清晰了。

有关树的生成,我把队友的画图代码封装成函数,用json数据存放成当前所有的树,最后一起生成防止生成关联树之后又生成关联树的子树,树的棵树用模块独立树减去关联树统计画出。

详细的生成树的逻辑思想见下面的流程图@lxy
学术家族树的前端实现_第4张图片

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

alert("宇宙最有价值的代码");

这就是最有价值的代码☝

正经一点开始正题

在上面的“算法的关键与关键实现部分流程图 ”我其实已经列出了一些代码都是一些功能函数

最有价值的就是主函数代码把,它。。多累啊

解释看注释和上面流程图

       //追逐函数

​        /*
​        分割传输过来的数据并构造json树结构
​        相当于主函数功能
​        */
​        function chase() {
​            var count = 0; //定义儿子节点的编号
​            var flag = 0; //定义标志是否为关联树值为1
​            var all_data = document.getElementById("user").value;
​            var sclice_data = [];
​            var model_data = [];
​            model_data = all_data.split("\n\n");
​            //生成树型结构数据
​            for (var j = 0; j < model_data.length; ++j) {
​                //初始化变量
​                count = 0;
​                //flag = 0;
​                quanju_flag = 0;
​                count_shu = 0
​                sclice_data = model_data[j].split("\n");
​                for (var i = 0; i < sclice_data.length; ++i) {
​                    var head_tmp = "";
​                    var body_tmp = "";
​                    var hb = sclice_data[i].split(":"); //从冒号分割一层字符串
​                    head_tmp = hb[0];
​                    body_tmp = hb[1];
​                    //处理冒号前的部分
​                    if (head_tmp == "导师") {
​                        var daoshi2 = {
​                            "name": body_tmp,
​                            "parent": "null",
​                            "children": [{}]
​                        }
​                        treeData[j] = daoshi2; //将导师嵌入节点
​                    } else {
​                        var children = {
​                            "name": head_tmp,
​                            "parent": "null",
​                            "children": [{}]
​                        }
​                        treeData[j].children[count] = children; //将年级及职业嵌入节点
​                        var bodies = body_tmp.split("、");
​                        //document.write("姓名:");
​                        for (var kk = 0; kk < bodies.length; ++kk) {
​                            var children = {
​                                    "name": bodies[kk],
​                                    "parent": "null",
​                                    //"children": [{}]
​                                }
​                                //treeData.push(children);
​                            treeData[j].children[count].children[kk] = children; //将姓名嵌入节点
​                        }
​                        count++; //第二子节点编号加一,生成下一个第二子节点
​                    }
​                }
​                var tree_tmp = treeData[j];
​                var name_tmp = treeData[j].name;
​                for (num_tmp = 0; num_tmp < j; num_tmp++) {
​                    check(treeData[num_tmp], name_tmp, tree_tmp, num_tmp);
​                }
​                if (!quanju_flag) count_shu++;//若有关联树则独立树的棵数不增加
​            }
​            //生成所有树
​            alert("shu: " + count_shu);
​            for (var i = 0; i <= count_shu; i++) {
​                shuInit(i)
​            }
​        }

附加特点设计与展示

设计的创意独到之处以及设计的意义

  • 采用透明图片作为背景,增加界面的美观感
  • 左右四六分的格局,使界面显得整齐规整
  • 蓝绿透明框配色,极具简约感
    -支持多颗关联树

实现思路

  • 用不同的div构建层次

  • css样式使用百分比宽高绝对定位
  • 算法和js操作详细请见上面的介绍

实现成果展示

  • 前端输入界面:

  • 生成树状结构界面:

  • 家族树缩放界面:

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

说明你的目录是如何组织的

目录

  • FT4.0
    • index.html(在chrome上运行)
    • style.css(外部样式表)
    • tree.js(生成家族书的函数)
    • background.jpg(背景图片)
    • d3.v3.min.js(d3库)
  • README:使用说明文件
  • 使用方式

    下载FT4.0到本地,解压后文件本地,用chrome打开index.html,在右侧文本框输入文本。

    学术家族树以文本形式输入,点击提交文本框。

  • 文本格式

    输入:

    学术家族树以文本形式输入,点击提交文本框,考虑学术家族树的文本格式是这样的:

    导师:张三

    2016级博士生:天一、王二、吴五

    2015级硕士生:李四、王五、许六

    2016级硕士生:刘一、李二、李三

    2017级本科生:刘六、琪七、司四

    导师:吴五
    2016级博士生:天一、王二、吴

    2015级硕士生:李四、王五、许六

    2016级硕士生:刘一、李二、李三

    2017级本科生:刘2、琪七、司四

    导师:刘2
    2016级博士生:天一、王二

    2015级硕士生:李四、王五、许六

    2016级硕士生:刘一、李、李三

    2017级本科生:刘、琪七、司四

    !!!文本最后不能换行

    其中,"导师:","级博士生:","级硕士生:","级本科生:"和"、"当做关键词处理;若有多组输入,中间空一行。

    输出:

    树的节点,鼠标点击后是可以缩放的。同时,支持呈现多棵树并存、两棵关联树共存等形式。

    在左侧家族树下会显示可缩放的树状结构,即生成的家族树。

测试人员如何运行你的网页

  • 点击github上把文件Clone到本地,解压后即可使用,需保证上述所有文件在同一个文件夹下。
  • 直接用Chrome打开indext.html,输入格式按照作业要求。
  • 在右侧的文本框输入数据,点击提交文本,将会在左侧生成一棵以导师为根节点的树。支持多棵树并存以及关联树。

单元测试

说明你们选用的测试工具,是如何学习单元测试的,能出一份你自己的简易教程吗?

展示出项目部分单元测试代码,并说明测试的函数

说明构造测试数据的思路,你是如何考虑各种情况的?你如何考虑将来测试人员的刁难?

单元测试,说实话多这个东西十分的陌生,虽然在上次的数独中有单元测试的一点点模块,助教大神不给我分啊气,这次希望助教大神。。。给点分,(憨憨只想开个玩笑,大神别搞我。这次单元测试也是相对比较简单的。

单元测试也花了不少时间,我在查找了很多js单元测试的框架之后选定了抹茶,mocha!多好的名字,我想必打起来也会和吃抹茶一样。

测试工具:mocha

我首先对我的求json树长度函数进行了测试,测试了两种情况

上图把

1子节点

2子节点的子节点

学术家族树的前端实现_第5张图片

学术家族树的前端实现_第6张图片

可见,虽然。。。。。但是都成功单元测试出来了,说明我的json树求长度功能还是可以的。

然后我又对子节点查找函数进行了测试

查找 子节点的子节点 的姓名

然后出现了我快要笑死的东西
学术家族树的前端实现_第7张图片

什么,竟然错了,在凌晨的四点的福大,仰望床底的我不禁开始了静静的思考

思考后并且和前面的比对之后我发现少加了东西,因为我是在单元测试.js中外部请求了函数模块,所以要加上module,鸭嘞鸭嘞,然后我愉快的加上了model。。。 -------》to be comtinue

学术家族树的前端实现_第8张图片

这个这个我竟看了老半天才发现,真的是xsl

学术家族树的前端实现_第9张图片

学术家族树的前端实现_第10张图片

测试成功,在所有子节点中以及子节点的子节点等等可以找到了名字为“yyy”的同学

然后我测试一下在所有的子节点中找到 陆小爷 同学

学术家族树的前端实现_第11张图片

果然,找不到陆小爷同学,因为他打软工去了。

测试成功。时间原因没有过多测试。

重点来了,下面可能是最入门级的单元测试教程

我仔细的浏览了一下博客作业中给出的mocha教程,发现很不容易上手(就是菜)

上手的教程在这哈哈哈哈哈

首先在电脑上安装node环境,并且配置环境变量path,(当然可以选择msi自行配制)

配置好之后就可以愉快的用npm命令啦,npm install mocha安装抹茶

配置抹茶.bin目录到path环境变量,然后就能愉快的运行你的test.js代码

关于断言的单元测试代码可以参考博客作业的教程。

//对单元测试当时爱了两个小时

构造单元测试的思路,和应对未来的刁难

思路清晰:

测试json长度为例,测试完根结点的长度,是否能测出子节点的长度呢。

查找子节点,是否能遍历所有子节点进行查找呢

应对刁难:

如果我们角色互换,我会让你看看什么叫残忍!

//多学习,多做事。做到足够优秀,代码足够健壮。

贴出Github的代码签入记录

你以为是这样,我也想
学术家族树的前端实现_第12张图片
他其实长这样
学术家族树的前端实现_第13张图片

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

  • 问题描述:树状结构难以实现。

  • 尝试:学习VUE,D3等框架,寻找类似树状可折叠结构的模板,学习API使用。

  • 是否解决:已解决。

  • 问题描述:界面设计简单简陋,不堪入目,html+css不熟练。

  • 尝试:广泛寻找优质界面,并借鉴学习,在B站和菜鸟教程寻找入门教学资源,一步步慢慢学习建立。

  • 是否解决:已解决


  • 问题描述:无法与界面树进行数据交互

  • 尝试:学习json,用json做结构

  • 是否解决:已解决


  • 问题描述:对json完全不了解

  • 尝试:打码测试,测试节点,测试遍历等等learning by doing

  • 是否解决:玩6了


  • 问题描述:太瞌睡

  • 尝试:拉着队友一起熬夜

  • 是否解决:已解决,两人均变憨憨


评价队友

  • 值得学习的地方

    和我一样有着永不放弃的黄金精神,

  • 需要改进的地方

    不喜欢花里胡哨的东西,在基本代码还没实现之前就 不想着要搞事情。(兄嘚,Java得浪啊)

六组测试

数据一:

导师:张三

数据二:

导师:张三
2016级博士生:天一
2015级硕士生:李四
2016级硕士生:刘一
2017级本科生:刘六

数据三:

导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六

数据四:

导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四

数据五:

导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四

导师:吴五
2016级博士生:天一、王二、吴
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘2、琪七、司四

数据六:

导师:张三
2016级博士生:天一、王二、吴五
2015级硕士生:李四、王五、许六
2016级硕士生:刘一、李二、李三
2017级本科生:刘六、琪七、司四

导师:吴五
2016级博士生:天二、王四、吴六
2015级硕士生:李一、王八、许七
2016级硕士生:刘三、李八、李二
2017级本科生:刘一、琪八、司四九
导师:刘2
2016级博士生:天四、王九
2015级硕士生:李四
2016级硕士生:刘一
2017级本科生:刘一

长路漫漫,队友作伴

你可能感兴趣的:(学术家族树的前端实现)