• 软件工程实践2019第五次作业


    Part1.结对信息


    项目信息

    项目 地址
    本次作业 https://edu.cnblogs.com/campus/fzu/2019FZUSEZ/homework/8736
    Github项目 https://github.com/JiuSiZhang/021700827-071703323.git
    学号 姓名 博客地址
    021700827 张启荣 https://www.cnblogs.com/zhangjiusi/
    071703323 卢昱妃 https://www.cnblogs.com/0717fei/

    具体分工

    张启荣:设计框架,代码编写
    卢昱妃:UI设计,后期美化

    Part2.PSP表格


    PSP表格

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

    Part3.目录组织、使用说明


    使用说明

    在GitHub项目中下载2.html文件,打开即可使用
    突出强调:格式必须严格遵守约定,单组输入时结尾不加空行,多组输入时,每组数据之间必须有空行。

    目录说明

    代码主要使用了d3框架,使用d3有两种方法
    (1)下载 D3.js 的文件: d3.zip
    (2)还可以直接包含网络的链接:

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

    但使用的时候要保持网络连接有效,不能在断网的情况下使用。
    这次代码我们采用第二种方法,因此只需下载2.html,打开即可使用

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


    (1)算法的关键与关键实现部分流程图

    本次代码的关键在于如何读入数据,并将其转换为框架可以使用的对象。因为可能出现多棵树关联,多棵树独立存在等等较为复杂的情况,所以建树有些麻烦。首先,先按行提取,对关键字进行划分,关键字独立形成结点。正常情况下,每组数据应该生成三层的树,导师结点一层,所在学位一层,学位下学术一层。所以先提取导师结点,将学位结点添加至他地下吗,再对每个学位,添加哪些学生,由于一开始想法不严谨,借鉴了一些第一位同学的想法。

    (2)关键代码展示

    *以文本域方式获取数据:

    <label>师生信息:</label>
    		<textarea cols="50"rows="10"id="text"></textarea>
    		<input type="submit" value="确定"  name="submit" onclick="GetTextAreaValue()" />
    

    *对输入数据的处理:

                var str=document.all.text.value;//获取文本框的数据
                arrstr=str.split('
    ');//通过换行符分割
    			var next=new Map;//存边,第一维存名字,值是数据继续递归
    			var level=new Map;//存最高等级
    			var f=new Map;//存是否有父亲结点
    			var x=["博士生", "硕士生", "本科生"];//关键词
    			var vi=[];//存出现过的词
    			for(var i=0;i<arrstr.length;)
    			{
    				var j;
    				for(j=i;j<arrstr.length;j++)
    				{
    					if(arrstr[j]=="")
    					{
    						break;
    					}
    				}//到这边是一组数据
    				//第一层
    				var item=arrstr[i].split(':');//通过冒号分割
    				var tp=item[1];//导师结点
    				next[tp]=[];
    				level[tp]=item[0];
    			//	console.log(tp);
    				vi.push(tp);
    				for(var l=i+1;l<j;l++)//第二层
    				{
    					for(var val of x)
    					{
    						//console.log(val);
    						if(arrstr[l].indexOf(val)!=-1)//如果该关键字存在
    						{
    							var item1=arrstr[l].split(':');
    							var z=item1[0]+tp;
    							// console.log(z);
    							next[tp].push(z);//建边
    							level[z]=val;
    							next[z]=[];//新建边数组
    							f[z]=1;//标记有父亲
    							vi.push(z);//收集关键字
    							break;
    						}
    					}
    					
    					var s=item1[1].split('、');//通过顿号分割
    					for(var val of s)//第三层
    					{
    						//console.log(val);
    							next[z].push(val);
    							f[val]=1;
    							level[val]=item1[0];
    							vi.push(val);	
    					}
    				}
    				i=j+1;
    				
    			}
    			for(var val of vi)
    			{
    				
    				if(f[val]==null)
    				{
    				//	console.log(val);
    					var root=dfs(val,-1);//没有父亲的结点一定为根结点
    					//console.log(root);
    				}
    			}
    			function dfs(u,fa)//dfs递归建对象
    			{
    				var ss;
    				ss={};
    				ss.name=u;
    				ss.children=[];
    				var v=next[u];
    				if(v==null)
    				{
    					return ss;
    				}
    				for(var i=0;i<v.length;i++)
    				{
    					ss.children.push(dfs(v[i],u));
    				}
    				if(u.indexOf(fa)!=-1)
    				{
    					var t=u.substring(0, u.indexOf(fa));
    					ss.name=t;
    				}
    				return ss;
    			}
    

    *动画效果添加:实现树结点的伸展、缩放

    			  // Transition nodes to their new position.将节点过渡到一个新的位置-----主要是针对节点过渡过程中的过渡效果
    				  //node就是保留的数据集,为原来数据的图形添加过渡动画。首先是整个组的位置
    				  var nodeUpdate = node.transition()  //开始一个动画过渡
    					  .duration(duration)  //过渡延迟时间,此处主要设置的是圆圈节点随斜线的过渡延迟
    					  .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });//YES
    				 
    				 
    				  // Transition exiting nodes to the parent's new position.过渡现有的节点到父母的新位置。
    				  //最后处理消失的数据,添加消失动画
    				  var nodeExit = node.exit().transition()
    					  .duration(duration)
    					  .attr("transform", function(d) { return "translate(" + source.x + "," + source.y + ")"; })//YES
    					  .remove();
    				 
    				  // 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 = {y: source.x0, x: source.y0};//YES
    						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};//NO
    						return diagonal({source: o, target: o});
    					  })
    					  .remove();
    				 
    				  // Stash the old positions for transition.将旧的斜线过渡效果隐藏
    				  nodes.forEach(function(d) {
    					d.x0 = d.y;
    					d.y0 = d.x;
    				  });
    				}
    				 
    				//定义一个将某节点折叠的函数
    				// 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);
    				}
    			}
    

    Part5. 附加特点设计与展示


    (1)设计的创意独到之处,这个设计的意义

    *为每个结点填充头像
    *添加背景图片

    (2)实现思路

    通过d3库调用,设置相应参数信息

    (3)关键代码

    *自由设置界面背景

    d3.select("body").style("background-image", "url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1571756972&di=bdf0695f47523fcf88d876b50fa53608&imgtype=jpg&er=1&src=http%3A%2F%2Fpic1.16pic.com%2F00%2F39%2F66%2F16pic_3966891_b.jpg)");
    

    *对人物结点的头像填充

    	var defs = svg.append("defs").attr("id", "imgdefs")
    	var catpattern = defs.append("pattern")
    							.attr("id", "pat")
    							.attr("height", 1)
    							.attr("width", 1)
    							.attr("patternContentUnits","objectBoundingBox")
    
    	catpattern.append("image")
    			.attr("width", "1.4")
    			.attr("height", "1")
    			.attr("xlink:href", "http://img.mp.sohu.com/upload/20170612/817b54ced4694d61b7fc1b0111c75450_th.png")
    
    	return "url(#pat)";
    

    (4)成果展示

    Part6. 单元测试


    使用工具:mocha
    教程:https://blog.csdn.net/llmys/article/details/82562143 这个很简洁明了推荐。
    页面可以看到,所以直接对数据处理测试构建复杂数据

    var get_json = require('../get_json.js').get_json;
    var expect = require('chai').expect
    var str=`导师:张三
    2016级博士生:天一、王二、吴五
    2015级硕士生:李四、王五、许六
    2016级硕士生:刘一、李二、李三
    2017级本科生:刘六、琪七、司四
    2018级本科生:老张、妃妃
    2020级本科生:A、B、C
    
    导师:老张
    2025级本科生:a、b、c
    2026级博士生:x、y、妃妃
    
    导师:zp
    2005级博士生:张三`;
    var ans='{"name":"zp","children":[{"name":"2005级博士生","children":[{"name":"张三","children":[{"name":"2016级博士生","children":[{"name":"天一","children":[]},{"name":"王二","children":[]},{"name":"吴五","children":[]}]},{"name":"2015级硕士生","children":[{"name":"李四","children":[]},{"name":"王五","children":[]},{"name":"许六","children":[]}]},{"name":"2016级硕士生","children":[{"name":"刘一","children":[]},{"name":"李二","children":[]},{"name":"李三","children":[]}]},{"name":"2017级本科生","children":[{"name":"刘六","children":[]},{"name":"琪七","children":[]},{"name":"司四","children":[]}]},{"name":"2018级本科生","children":[{"name":"老张","children":[{"name":"2025级本科生","children":[{"name":"a","children":[]},{"name":"b","children":[]},{"name":"c","children":[]}]},{"name":"2026级博士生","children":[{"name":"x","children":[]},{"name":"y","children":[]},{"name":"妃妃","children":[]}]}]},{"name":"妃妃","children":[]}]},{"name":"2020级本科生","children":[{"name":"A","children":[]},{"name":"B","children":[]},{"name":"C","children":[]}]}]}]}]}';
    describe('测试数据处理函数', function() {
      it('生成的字符串应该等于ans', function() {
        expect(get_json()).to.be.equal(ans);
      });
    });
    

    Part7. Github的代码签入记录


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


    (1)问题描述

    一开始建树有问题,没办法处理复杂的数据情况
    无法生成多颗独立存在的树

    (2)做过哪些尝试

    找人问,找网上代码,看同学发布的博客

    (3)是否解决?

    第一点解决,数据可以完美生成,第二点未解决,无法生成两颗独立存在的树,一但出现这种情况,除最后一棵树外其他树将无法操作。

    (4)收获

    学到了d3库的使用方法,js的基本语法和应用,对象的处理,数据格式的转换。

    Part9.心得总结


    张启荣:
    评价一下我的队友
    值得学习的地方:谦虚好学,很有责任心,思维严谨而且做的页面很好看。
    需要改进的地方:两个人应该多一些沟通与交流。
    卢昱妃:
    十天速成一门新的语言是一个富有挑战的任务,自己的学习能力还有待提高,这次多亏有代码能力和学习能力都极强的队友全面帮助,才能使得项目推进如此顺利,通过这次结对,从队友身上学到了很多。结对训练完成以后还要继续加强前端的学习。个人觉得两个在结对配合和交流上还是十分顺畅,减少了交流故障造成的时间损耗,以后可以更多一点沟通与交流。

  • 相关阅读:
    045_List view button
    044_Schedule Job 间隔时间自动执行
    043_关于Salesforce集中权限的解释
    041_Record Type
    040_Field Set
    039_External Data Source(转载)
    037_Clone Button
    036_在salesforce中更换自定义app的logo
    020_Json的使用
    033_SFDC-Apex案例整理-未完
  • 原文地址:https://www.cnblogs.com/zhangjiusi/p/11699012.html
Copyright © 2020-2023  润新知