java+数据库+D3.js 实时查询人物关系图

先看下 效果

某个用户,邀请了自己的朋友 ,自己的朋友邀请了其他朋友,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 很火,这里做个参考

 

posted @ 2016-12-03 10:35  猪哥哥厉害  阅读(12895)  评论(0编辑  收藏  举报