先看下 效果
某个用户,邀请了自己的朋友 ,自己的朋友邀请了其他朋友,1 展示邀请关系,2 点击头像显示邀请人和被邀请人的关系。(网上这种资料很少, 另外很多都是从JSON文件取 数据, 这里是从数据库取数据)
=================================================================================================需求:Java从数据库查用户表,管理平台可以实时查看每个月用户的邀请关系图。
以下是代码:
1.Java 方法
1.1 controller 根据某个手机号码查出JSON
/**
* @param model
* @param mobile
* @return
*/
@RequestMapping(value = "/relation")
public ModelAndView toRelation(Model model,@RequestParam("mobile")String mobile) {
String userName= AuthUtils.getAuthenticationObject().getName();
Customer user =userService.getUserByname(userName);
model.addAttribute("role", user.getRole());
model.addAttribute("username", user.getMobile());
JSONObject json = customerService.findUserRelation(mobile);
model.addAttribute("json", json);
System.out.println(json);
return new ModelAndView("relation");
}
1.2 service 方法(递归查询,JSON处理)
/**
* 根据手机号码查询人物关系图
* @param mobile
* @return
*/
public JSONObject findUserRelation(String mobile) {
JSONObject json = new JSONObject();
// 首先查询当前用户
Customer customer = userService.getUserByname(mobile);
List<RelationBo> list = new ArrayList<RelationBo>();
// 根节点,只看子类
// 递归获取当前用户的所有子类。
list = getAllRelation(new ArrayList<RelationBo>(), customer.getUid());
list.add(0, new RelationBo(mobile,Constants.TOP_USER,
customer.getUid(), null));
// 获取用户信息JSONArray
JSONArray peopleArray = new JSONArray();
JSONArray targetArray = new JSONArray();
SourceTargetBo bo = null;
JSONObject peoJ= null;
List<String> photoList= RelationUtil.getRandomPhoto();
for (int i = 0; i < list.size(); i++) {
peoJ=new JSONObject();
peoJ.put("name", list.get(i).getName());
// peoJ.put("image", list.get(i).getImage());
peoJ.put("image", photoList.get(i));
peopleArray.add(peoJ);
for (int j = 0; j < list.size(); j++) {
if(list.get(j).getPuid()==null||list.get(j).getPuid()==list.get(i).getUid()){
continue;
}
if (list.get(i).getUid().equals(list.get(j).getPuid())) {
bo = new SourceTargetBo(i, j,"resolved",RelationUtil.getRelation());
// 找到子类序号
targetArray.add(bo);
}
}
}
// 人物JSON
json.put("nodes", peopleArray);
// 关系JSON
json.put("edges", targetArray);
return json;
}
private List<RelationBo> getAllRelation(List<RelationBo> bo, String uid) {
// 查询这个用户下的所有子用户
List<Customer> list = customerDao.findAllChild(uid);
RelationBo relation = null;
if (list == null || list.size() == 0) {
// 当前用户没有子用户了!
return bo;
} else {
for (Customer cus : list) {
relation = new RelationBo(cus.getMobile(), Constants.BOOTOM_USER,
cus.getUid(), cus.getPuid());
// 所有子用户添加到树中
bo.add(relation);
// 递归查询子用户的所有子用户
bo = getAllRelation(bo, cus.getUid());
}
}
return bo;
}
1.3 mybatis
<select id="findAllChild" resultType="com.ycmedia.entity.Customer">
select * from r_user where puid=#{uid}
</select>
1.4 数据库 因为数据库暂时没有用户头像,所以随机工具类定义了几个头像
1.5 工具类, 获得随机关系, 用户头像
package com.ycmedia.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RelationUtil {
public static String getRelation(){
List<String> list = new ArrayList<String>();
list.add("");
list.add("亲人");
list.add("同学");
list.add("朋友");
list.add("同事");
list.add("邻居");
int Num=new Random().nextInt(4)+1;
return list.get(Num);
}
public static List<String> getRandomPhoto(){
List<String> list = new ArrayList<String>();
list.add("http://apps.ycmedia.cn/qm/img/31f96dc747eb4e4383ab7f990afc9775.jpg");
list.add("http://appdemo.b0.upaiyun.com/qm/img/lable/60x60/1480730644618.jpg");
list.add("http://appdemo.b0.upaiyun.com/qm/img/lable/60x60/1480730825975.jpg");
list.add("http://appdemo.b0.upaiyun.com/qm/img/lable/60x60/1480730901129.jpg");
list.add("http://appdemo.b0.upaiyun.com/qm/img/lable/60x60/1480730947894.jpg");
return list;
}
}
1.7 最后的JSON格式
=========================以上是Java, 下面是 html
2.1 html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>邀请关系图</title>
<style>
.nodetext {
font-size: 12px ;
font-family: SimSun;
fill:#000000;
}
.linetext {
font-size: 12px ;
font-family: SimSun;
fill:#0000FF;
fill-opacity:0.0;
}
path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
marker#licensing {
fill: green;
}
path.link.licensing {
stroke: green;
}
path.link.resolved {
stroke: green;
}
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
text.shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .8;
}
</style>
</head>
<body>
<input type="hidden" th:value="${json}" id="json" />
<script src="/bootstrap/jQuery/jquery-2.2.3.min.js"></script>
<script src="/js/d3.v3.min.js" charset="utf-8"></script>
<script>
var obj=$("#json").val();
var root = JSON.parse(obj);
var width = 1200;
var height = 1200;
var img_w = 77;
var img_h = 90;
var svg = d3.select("body").append("svg:svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.nodes(root.nodes)
.links(root.edges)
.size([width,height])
.linkDistance(200)
.charge(-1500)
.start();
//控制线条
var edges_line = svg.selectAll("line")
.data(root.edges)
.enter()
.append("line")
.style("stroke","#ccc")
.style("stroke-width",1);
//控制文字
var edges_text = svg.selectAll(".linetext")
.data(root.edges)
.enter()
.append("text")
.attr("class","linetext")
.text(function(d){
return d.relation;
});
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
//控制图片
var nodes_img = svg.selectAll("image")
.data(root.nodes)
.enter()
.append("image")
.attr("width",img_w)
.attr("height",img_h)
.attr("xlink:href",function(d){
return d.image;
})
.on("mouseover",function(d,i){
edges_text.style("fill-opacity",function(edge){
if( edge.source === d || edge.target === d ){
return 1.0;
}
});
})
.on("mouseout",function(d,i){
edges_text.style("fill-opacity",function(edge){
if( edge.source === d || edge.target === d ){
return 0.0;
}
});
})
.call(force.drag);
var text_dx = -20;
var text_dy = 20;
var nodes_text = svg.selectAll(".nodetext")
.data(root.nodes)
.enter()
.append("text")
.attr("class","nodetext")
.attr("dx",text_dx)
.attr("dy",text_dy)
.text(function(d){
return d.name;
});
force.on("tick", function(){
edges_text.attr("x",function(d){ return (d.source.x + d.target.x) / 2 ; });
edges_text.attr("y",function(d){ return (d.source.y + d.target.y) / 2 ; });
nodes_img.attr("x",function(d){ return d.x - img_w/2; });
nodes_img.attr("y",function(d){ return d.y - img_h/2; });
nodes_text.attr("x",function(d){ return d.x });
nodes_text.attr("y",function(d){ return d.y + img_w/2; });
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,//增量
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y + "A" + dr + ","
+ dr + " 0 0,1 " + d.target.x + ","
+ d.target.y;
});
});
</script>
</body>
</html>
以上就是全部代码, 目前未实现箭头,昨天搞了好长时间, 没弄出来, Java的画图工具不行, 太丑, 现在D3Js 很火,这里做个参考