d3鼠标拖拽、放大缩小后动态加载页面数据demo

index.html

 

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #keyword{
          height: 90%;
          width: 95%;
          position: absolute;
          top: 55px;
          bottom: 0px;
         z-index: 0;
         overflow:hidden; 
         word-break:break-all;
        }
      #keyword2{
         height: 90%;
         width: 95%;
         position: absolute;
         top: 55px;
         bottom: 0px;
         z-index: 0;
         overflow:hidden;
         word-break:break-all;
      }
        .link {
            fill: none;
            stroke: #666;
            stroke-width: 1.5px;
        }
        #licensing {
            fill: green;
        }
        .link.licensing {
            stroke: green;
        }
        .link.resolved {
            stroke-dasharray: 0,2 1;
        }
        circle {
            stroke: #333;
            stroke-width: 1.5px;
        }
        text {
            font: 12px Microsoft YaHei;
            pointer-events: none;
            text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
        }
        .linetext {
            font: 12px Microsoft YaHei;
        }
        .mytooltip{
            position: absolute;
            height: auto;
            font-family: "microsoft yahei", simhei;
            font-size: 14px;
            text-align: center;
            border: 1px solid #999;
            padding: 5px;
            background-color: white;
            border-radius: 5px;
         opacity:0.0;
        }
      #gallery {
         width: 200px;
         height: 200px;
         /*background: url('img/1.JPG') no-repeat center center;

         background-size:100%;

         font-size:30px;

         color:#fff;*/
         text-align:center;
         /*line-height:200px;*/
      }
    </style>
   <link rel="stylesheet" type="text/css" href="css/easyui.css">
   <link rel="stylesheet" type="text/css" href="css/icon.css">
</head>
<body>
<div title="资产地图展示" >
   <div id="keyword">
   </div>
</div>
   <div class="mytooltip" id="imgtooltip"></div>
   <script src="assets/plugins/jquery/jquery-3.3.1.min.js"></script>
   <script src="assets/plugins/jquery.easyui.min.js"></script>
   <script src="assets/plugins/d3/d3.v3.min.js"></script>
   <script src="assets/js/pages/index.js"></script>
</body>
</html>

index.js

 

   var root = {};
  
var nodesbak = {};
  
var colorObj = {};
  
var imgtype = 0;
  
var maxValue = 0;//最大的那个系统
  
$(function (){
       $.getJSON(
"assets/data/word.json", function (data){
          
root = deepClone(data,{});
          
//系统备份
          
root.nodes.concat().forEach(function(node,k) {
              
if(node.value > maxValue){
                  
maxValue = node.value;
               }
              
colorObj[node.id] = k;
              
nodesbak[node.id] = {name:node.id,group:node.group,x1:node.x,y1:node.y,type:node.id,value:node.value};
           });
          
//表备份
          
root.nodes1.concat().forEach(function(node,k) {
              
nodesbak[node.id] = {name:node.id,group:node.group,x1:node.x,y1:node.y,pid:node.pid,type:node.pid};
           });
          
//画系统布局图
          
draw(root.nodes,root.links,sys_transform,sys_scale);

       })
   })

  
var links = [];//关联关系
  
var nodes = {};//节点数据

  
var initscale = 1;//保留一份最初始的缩放系数,用于放大时计算最近距离
  
var sys_scale = 1;//域、系统放大时的缩放倍数
  
var sys_transform = [0,0];//域、系统放大时的中心坐标
var tab_scale = 1;//表放大时的缩放倍数
  
var tab_transform = [0,0];//表放大时的中心坐标

  
var edges_line = null;//连接线
var circle = null;//节点
var edges_text = null;//连接线上的文字
var text = null;//节点文字

var svg = null;
var force = null;//力学图对象
  
var zoom = null;//缩放配置

var dx = 0;//x偏移量
var dy = 0;//y偏移量
  
var ds = 1;//放大缩小倍数

var m_down_x ;//拖拽前x
var m_down_y ;//拖拽前y
var m_move_x ;//拖拽后x
var m_move_y ;//拖拽后y

var isDown = false;//记录鼠标状态

  
var width = '100%',height = '100%';
  
var type = '1';//'1':域、系统;'2':
//格式化数据
function formatData(paramNodes,paramLinks){
      
var m = 0;
      
var copynodes = deepClone(nodesbak,{});
       paramNodes.
forEach(function(node,k) {
          
var x = copynodes[node.id].x1;
          
var y = copynodes[node.id].y1;
          
if(x*ds+dx > 0 && x*ds+dx < screen.width
               &&
y*ds+dy > 0 && y*ds+dy < (screen.height -280) && m < 500/ds
          
){
              
nodes[node.id] = {name: node.id,group:node.group,x1:x,y1:y,type:(type ==1?node.id:node.pid)};
              
m++;
           }
          
return;
       });
  
for(var i=0;i<paramLinks.length;i++){
     
if(nodes[paramLinks[i].source] != null && nodes[paramLinks[i].target] != null){
        
links.push({
              
source: paramLinks[i].source,
              
target: paramLinks[i].target,
              
rela: paramLinks[i].value
          
})
      }
    }

  
links.forEach(function(link) {
       
//利用sourcetarget名称进行连线以及节点的确认
       
link.source = nodes[link.source];
        link.
target = nodes[link.target];
    });

}

  
function zoomed(){//缩放函数

      
svg.selectAll("g").attr("transform",//svg下的g标签移动大小
          
"translate("  +d3.event.translate + ")scale(" +d3.event.scale + ")");
      
if (d3.event.scale == 10 && type == 1){//放大到最大就切换页面
         
enlargePage();
         
return;
       }
if(d3.event.scale == 0.4 && type == 2 ){//缩小到最大就切换页面
         
reducePge();
         
return;
       }

      
var dxy = d3.event.translate;

      
dx = dxy[0];
  
dy = dxy[1];
  
if(ds != d3.event.scale && d3.event.scale >0.1 && d3.event.scale <5){
          
ds = d3.event.scale;
          
svg.selectAll('g').remove();
           d3.
select("#keyword").selectAll("svg").remove();
           draw(
root.nodes,root.links,[dx,dy],ds);
       }
   }

//放大页面,切换操作
function enlargePage(){
  
if(type == '1'){//域、系统切换到表
     
type = '2';//切换到表的页面
     
sys_scale = d3.event.scale;//域、系统放大时的缩放倍数
        
sys_transform = d3.event.translate;//域、系统放大时的中心坐标
     
svg.selectAll('g').remove();
      d3.
select("#keyword").selectAll("svg").remove();
          
//放大时,取到当前鼠标最近的某个域或者系统
          
//源坐标
          
var position = [d3.event.sourceEvent.clientX/((screen.width -100)/1366), d3.event.sourceEvent.clientY/((screen.height -280)/768)];
          
var x1 = position[0]*10;
          
var y1 = position[1]*10;
          
//目标坐标
          
var x2 = screen.width/2;
          
var y2 = 950/2;
          
//偏移量
          
dx = x2-x1;
          
dy = y2-y1;
          
ds = 1;
           draw(
root.nodes1,root.links1,[dx,dy],ds);
           $(
"#img_id").show();
           getSysByXy(
position[0],position[1]);
          
tooltip.style("opacity",0.0);
   }
}

//缩小页面,还原操作
function reducePge(){
  
if(type == '2'){//表切换到域、系统
     
type = '1';
     
svg.selectAll('g').remove();
      d3.
select("#keyword").selectAll("svg").remove();

      draw(
root.nodes,root.links,sys_transform,sys_scale);
          
tooltip.style("opacity",0.0);
   }
}


//绘制图像
  
function draw(paramNodes,paramLinks,paramTransform,paramScale) {
      
tooltip ?tooltip.html(""):tooltip;

      
nodes = {};
      
links = [];
      
edges_line = null;//连接线
      
circle = null;//节点
      
edges_text = null;//连接线上的文字
      
text = null;//节点文字

      
formatData(paramNodes,paramLinks);

  
force = d3.layout.force()//layoutjson格式转化为力学图可用的格式
      
.nodes(d3.values(nodes))//设定节点数组
      
.links(links)//设定连线数组
      
.size([width, height])//大小
      
.linkDistance(120)//连接线长度
      
.charge(-600)//值为+,则相互吸引,绝对值越大吸引力越大。值为-,则相互排斥,绝对值越大排斥力越大
      
.on("tick", tick)//开始转换
  
.start();

  
zoom = d3.behavior.zoom()//缩放配置,
      
.scaleExtent([0.4, 10])//缩放比例
      
.on("zoom", zoomed);

  
svg = d3.select("#keyword").append("svg")//添加svg元素进行图形的绘制
      
.attr("width", width)
       .attr(
"height", height)
       .
call(zoom)
       .on(
"mousedown",function(event){
          
isDown = true;
          
//获取鼠标按下时坐标
          
m_down_x = d3.event.pageX;//拖拽前x
          
m_down_y = d3.event.pageY;//拖拽前y
      
})
       .on(
"mousemove",function(){
          
//获取鼠标移动实时坐标
          
m_move_x = d3.event.pageX;
          
m_move_y = d3.event.pageY;

       })
       .on(
"mouseup",function(){
          
isDown = false;
          
var mx = m_move_x - m_down_x;
          
var my = m_move_y - m_down_y;
          
//获取鼠标偏移量
          
if(mx != 0 || my != 0){
              
//有偏移量的情况下,再去加载数据
              
svg.selectAll('g').remove();
               d3.
select("#keyword").selectAll("svg").remove();
               draw(
root.nodes,root.links,[dx,dy],ds);

           }

       });
//使顶点可以被拖动;//使顶点可以被拖动;

       //
箭头
      
var marker=
          
svg.append("marker")
               .attr(
"id", "resolved")
               .attr(
"markerUnits","userSpaceOnUse")
               .attr(
"viewBox", "0 -5 10 10")//坐标系的区域
              
.attr("refX",18)//箭头坐标
              
.attr("refY", -1)
               .attr(
"markerWidth", 12)//标识的大小
              
.attr("markerHeight", 12)
               .attr(
"orient", "auto")//绘制方向,可设定为:auto(自动确认方向)和 角度值
              
.attr("stroke-width",2)//箭头宽度
              
.append("path")
               .attr(
"d", "M0,-5L10,0L0,5")//箭头的路径
              
.attr('fill','#000000');//箭头颜色


      
edges_line = setLine();//设置连接线
      
circle = setTabNode();//设置节点
  
edges_text = setEdgesText();//设置连接线上的文字
  
text = setText();//设置节点文字

  
svg.selectAll("g").attr("transform",//svg下的g标签移动大小
  
"translate("+paramTransform.toString()+")scale("+paramScale+")");

  
zoom.translate(paramTransform);
  
zoom.scale(paramScale);

  
svg.selectAll("g").call(drag());//svg下的所有g标签添加拖拽事件
      
svg.on("dblclick.zoom", null);//取消svg和圆圈的双击放大事件(d3中默认开启7个事件,关闭防止与上面的双击事件冲突)
      
circle.on("dblclick.zoom", null);
   }

  
//设置连接线
  
function setLine(){
      
var edges_line = svg.append("g").selectAll(".edgepath")
           .
data(force.links())//连线数据
          
.enter()//当数组中的个数大于元素个数时,由d3创建空元素并与数组中超出的部分进行绑定。
          
//可以参考http://www.ourd3js.com/wordpress/797/ enterexitupdate的区别
          
.append("path")//添加path标签
          
.attr({
              
'd': function(d) {
                  
return 'M '+d.source.x1+' '+d.source.y1+' L '+ d.target.x1 +' '+d.target.y1},//变量 d 是由D3.js提供的一个在匿名函数中的可用变量。这个变量是对当前要处理的元素的_data_属性的引用。
              
'class':'edgepath',//定义该path标签classedgepath
              
'id':function(d,i) {return d.source.name+"_"+d.target.name;},
              
'rid':function(d,i) {return d.source.name;},
              
'sid':function(d,i) {return d.target.name;}
           })
// i也是d3.js提供的变量,表示当前处理的HTML元素在已选元素选集中的索引值
          
.attr("marker-end", "url(#resolved)")
           .style(
"stroke","#B43232")//设置线条颜色
          
.style("stroke-width",0.5);//线条粗细
          
return edges_line;
   }

  
function drag(){//拖拽函数
      
return force.drag()
           .on(
"dragstart",function(d){
               d3.event.sourceEvent.
stopPropagation(); //取消默认事件
              
d.fixed = true;    //拖拽开始后设定被拖拽对象为固定

          
});
   }

  
//圆圈的提示文字 根据需要到数据库中进行读取数据
  
var tooltip = d3.select("body")
       .
append("div")//添加div并设置成透明
      
.attr("class","mytooltip")
       .style(
"opacity",0.0);
  
var localColor = d3.scale.category20();

//设置域、系统图片
  
function setTabNode(){
      
var circle = svg.append("g")
       .selectAll(
"circle")
       .
data(force.nodes())//表示使用force.nodes数据
      
.enter()
       .
append("circle")
       .attr(
"class", "circle")
      
/*.attr("transform", function(node,i){
           return "translate("+node.x1+","+node.y1+")";
       })*/
      
.attr("cx", function(node,i){
          
return node.x1;
       })
       .attr(
"cy", function(node,i){
          
return node.y1;
       })
       .attr(
"id", function(node,i){
          
return node.name;
       })
       .attr(
"r",function(node,i){
          
if(node.group == 1 || node.group == 2){
              
if(nodesbak[node.name].value == maxValue){//最大
                  
return 20;
               }
else if(nodesbak[node.name].value/(maxValue/20) < 3){//最小
                  
return 3;
               }
else{
                  
return nodesbak[node.name].value/(maxValue/20);
               }
           }
else{
              
return 3;
           }

       })
//设置圆圈半径
      
.style('fill',function (node,i) {

          
return localColor(colorObj[node.type]);
       })
       .on(
"click",function(node){
          
//单击时让连接线加粗
          
edges_line.style("stroke-width",function(line){
              
if(line.source.name==node.name || line.target.name==node.name){//当与连接点连接时变粗
                  
return 2;
               }
else{
                  
return 2.5;
               }
           });
          
circle.style('stroke-width',1);//所有的圆圈边框
          
d3.select(this).style('stroke-width',4);//被选中的圆圈边框
      
})
       .on(
"dblclick",function(d){
          
//双击节点时节点恢复拖拽
          
d.fixed = false;
       })
       .on(
"mouseover",function(d){
           set_tooltip(d.
name);
       })
       .on(
"mousemove",function(d){
          
tooltip.style("left", (d3.event.pageX) + "px")
               .style(
"top", (d3.event.pageY + 20) + "px");
       })
       .on(
"mouseout",function(d){
          
tooltip.style("opacity",0.0);
       })
       .
call(drag());//使顶点可以被拖动

      
return circle;
   }


//设置圆圈上的文字
function setText(){
  
var text = svg.append("g").selectAll("text")
       .
data(force.nodes())
      
//返回缺失元素的占位对象(placeholder),指向绑定的数据中比选定元素集多出的一部分元素。
      
.enter()
       .
append("text")//添加text标签
      
.attr("dy", ".35em") //将文字下移
      
.attr("text-anchor", "middle")//在圆圈中加上数据
      
.style('fill',function (node,i) {
          
return localColor(colorObj[node.type]);
       })
       .style(
'cursor',"pointer")
       .attr(
'id',function(d){return 'text_'+d.name;})
       .attr(
"transform", function(node,i){
          
return "translate("+node.x1+","+node.y1+")";
       })
       .on(
"mouseover",function(d){
           set_tooltip(d.
name);
       })
       .on(
"mouseout",function(d){
          
tooltip.style("opacity",0.0);
       })
       .
call(drag())
       .attr(
'x',function(d){
          
//如果小于6个字符,不换行
          
if(d.name.length <= 6){
               d3.
select(this).append('tspan')
                   .attr(
'x',6)
                   .attr(
'y',35)
                   .
text(function(){return d.name;});
           }
else if(d.name.length > 12){//大于12个字符时,将12个字后的内容显示为。。。
              
var top=d.name.substring(0,6);
              
var bot=d.name.substring(6,12)+"...";
               d3.
select(this).text(function(){return '';});
               d3.
select(this).append('tspan')//n个字
                  
.attr('x',0)
                   .attr(
'y',35)
                   .
text(function(){return top;});
               d3.
select(this).append('tspan')//n个字
                  
.attr('x',0)
                   .attr(
'y',52)
                   .
text(function(){return bot;});

           }
else {//6-12字符分两行显示
              
var top=d.name.substring(0,6);
              
var bot=d.name.substring(6,d.name.length);
               d3.
select(this).text(function(){return '';});
               d3.
select(this).append('tspan')
                   .attr(
'x',0)
                   .attr(
'y',35)
                   .
text(function(){return top;});

               d3.
select(this).append('tspan')
                   .attr(
'x',0)
                   .attr(
'y',52)
                   .
text(function(){return bot;});
           }

       });
      
return text;
}


//连线上的文字
  
function setEdgesText(){
      
var edges_text = svg.append("g").selectAll(".edgelabel")
       .
data(force.links())
       .enter()
       .
append("text")//添加text标签
      
.attr({  'class':'edgelabel',//定义该text标签classedgelabel
          
'id':function(d,i){return 'edgepath_'+i;},
          
'dx':50,//在连线上的坐标
          
'dy':0
      
});

     
//设置线条上的文字路径
     
edges_text.append('textPath')
       .attr(
'xlink:href',function(d,i) {return '#edgepath_'+i})
       .style(
"pointer-events", "none")
       .
text(function(d){return d.rela;});
      
return edges_text;
   }

  
function tick() {//刷新页面函数

  
}

  
function set_tooltip(name){//设置提示内容
      
var r;
      
for(var i=0;i<links.length;i++){
          
if(name == links[i].source.name || name == links[i].target.name){
              
r=links[i].rela;
              
break;
           }
       }
      
tooltip.html(name)
           .style(
"left", (d3.event.pageX) + "px")
           .style(
"top", (d3.event.pageY + 20) + "px")
           .style(
"opacity",1.0);
   }



function deepClone(obj1,obj2){
      
var obj2=obj2||{}; //最初的时候给它一个初始值=它自己或者是一个json
      
for(var name in obj1){
          
if(typeof obj1[name] === "object"){ //先判断一下obj[name]是不是一个对象
              
obj2[name]= (obj1[name].constructor===Array)?[]:{}; //我们让要复制的对象的name=数组或者是json
              
deepClone(obj1[name],obj2[name]); //然后来无限调用函数自己 递归思想
          
}else{
              
obj2[name]=obj1[name];  //如果不是对象,直接等于即可,不会发生引用。
          
}
       }
      
return obj2; //然后在把复制好的对象给return出去
}

  
//设置圆圈和文字的坐标
  
function transform1(d) {
      
return "translate(" + d.x + "," + d.y + ")";
   }

 

猜你喜欢

转载自blog.csdn.net/qq_25927437/article/details/82992992
今日推荐