数据可视化 D3 力导向图鼠标右击菜单的制作及缩放(zoom)和拖拽(drag)的应用

先展示一波最终效果

最终效果

在这里插入图片描述

这段时间再学习D3,力导向图

力导向图(Force-Directed Graph),是绘图的一种算法。在二维或三维空间里配置节点,节点之间用线连接,称为连线。各连线的长度几乎相等,且尽可能不相交。节点和连线都被施加了力的作用,力是根据节点和连线的相对位置计算的。根据力的作用,来计算节点和连线的运动轨迹,并不断降低它们的能量,最终达到一种能量很低的安定状态。

力导向图能表示节点之间的多对多的关系。

定义一个力导向图的布局关键方法 force()
d3在v3和v4版本上对于 force() 这个方法变动很大

话不多说,代码如下:(注意:这次使用的D3.js版本是V3的)

           代码不是最终代码,但是功能基本已经实现,后续会更新这一版的最终代码

页面代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>The END</title>
  <script src="http://d3js.org/d3.v3.min.js"></script>
  <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
  <script src="./js/smartMenu.js"></script>
  <script src="./fun.js"></script>
  <link rel="stylesheet" href="./css/smartMenu.css">
</head>
<body>
  <div id="tpContainer">

  </div>   
 
</body>
</html>

力导向图代码 fun.js

//获取数据
d3.json('./preson.json', function(error,data){
  if (error) {
      return console.log(error);
    }
  // console.log(data);
  drawToPofun(data.nodes,data.lines);
});

function drawToPofun(nodes,edges){
  
  //定义初始变量
  var width  = 1503;
  var height = 654;
  var img_w = 40;
  var img_h = 40;
  var text_dx = -20;
  var text_dy = 20;
  var i = 0;

  //初始化拖拽方法
  var drag = d3.behavior.drag()
    .origin(function(d) {
      return d;
    })
    .on("dragstart", dragstarted)
    .on("drag", dragged)
    .on("dragend", dragended);

  //初始化缩放方法
  var zoom=d3.behavior.zoom()
    .scaleExtent([-10,10]).on("zoom",zoomed);

  //定义画布
  var svg = d3.select("#tpContainer")
  .append("svg")
  .attr("width",width)
  .attr("height",height)
  .call(zoom)
  .on("dblclick.zoom", () => {});//禁止双击放大
  
  //拆分子节点
  var view = svg.append("g")
  .attr("class","graphCon");
  
  var node = view.selectAll("g.node").data(nodes,function (d) {
    return d.id || (d.id = ++i);
  });

  var nodeEnter = node
  .enter()
  .append("g")
  .attr("class","node")
  .attr("id",d=>d.id)//添加节点,以自定义图标代替
  var nodes_img = nodeEnter.append("image")
  .data(nodes)
  .attr("width",function(d){
      return img_w;
    })
  .attr("height",function(d){
      return img_h;
    })
  .attr("xlink:href",function(d){
    return d.image;
    })
  .call(drag)//开始拖拽方法
  
  //添加连线
  var edges_line = nodeEnter.append("line")
  .data(edges)
  .attr("class","line")
  .style("stroke","#ccc")
  .style("stroke-width",1);

  //添加节点说明(文本)
  var nodes_text = nodeEnter.append("text")
  .data(nodes)
  .attr("class","nodetext")
  .attr("dx",text_dx)
  .attr("dy",text_dy)
  .text(function(d){
    return d.name;
  });

  //定义力学图布局
   var force  = d3.layout.force().nodes(nodes)
    .links(edges)
    .size([width,height])
    .linkDistance(200)
    .charge(-800)
    .start()
    .on("tick", function(){
      
      //限制结点的边界
      nodes.forEach(function(d,i){
        d.x = d.x - img_w/2 < 0? img_w/2 : d.x ;
        d.x = d.x + img_w/2 > width ? width - img_w/2 : 
        d.x ; 
        d.y = d.y - img_h/2 < 0? img_h/2 : d.y ;
        d.y = d.y + img_h/2 + text_dy > height ? 
        height - img_h/2 - text_dy : d.y ;
      });

      //更新连接线的位置
      edges_line.attr("x1",function(d){ return d.source.x; });
      edges_line.attr("y1",function(d){ return d.source.y; });
      edges_line.attr("x2",function(d){ return d.target.x; });
      edges_line.attr("y2",function(d){ return d.target.y; });
      //更新结点图片和文字
      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_h/2; 
      });
    }); 

    // 定义菜单选项
    var userMenuData = [
      [{
          text: "菜单1",
          func: function () {
            var id = Number($(this).attr("id"))
            alert("菜单1"+",No."+ id)
          }
        },
        {
          text: "菜单2",
          func: function () {
            var id = Number($(this).attr("id"))
            alert("菜单2"+",No."+ id)
          }
        },
        {
          text: "菜单3",
          func: function () {
            var id = Number($(this).attr("id"))
            alert("菜单3"+",No."+ id)
          }
        } 
      ]
    ];
    // 事件监听方式添加事件绑定
    $("body").smartMenu(userMenuData, {
      name: "chatRightControl",
      container: "g.node"
    });
    
    function zoomed(){
      view.attr("transform",
      "translate("+d3.event.translate+")scale(" +
      d3.event.scale + ")");
    }
    function dragstarted(d) {
      d3.event.sourceEvent.stopPropagation();
      d3.select(this).classed("dragging", true);
      force.start();
    }
    function dragged(d) {
      d.x = d3.event.x;
      d.y = d3.event.y;
    }
    function dragended(d) {
      d3.select(this).classed("dragging", false);
    }
}

数据格式 preson.json

{
  "nodes": [
    {"name": "preson1", "image": "./person.png"}, 
    {"name": "preson2", "image": "./person.png"}, 
    {"name": "preson3", "image": "./person.png"}, 
    {"name": "preson4", "image": "./person.png"}, 
    {"name": "preson5", "image": "./person.png"}, 
    {"name": "preson6", "image": "./person.png"},
    {"name": "preson7", "image": "./person.png"},
    {"name": "preson8", "image": "./person.png"},
    {"name": "preson9", "image": "./person.png"},
    {"name": "preson10","image": "./person.png"}
],
"lines": [
  { "source": 0 , "target": 1 },
  { "source": 0 , "target": 2 },
  { "source": 0 , "target": 3 },
  { "source": 1 , "target": 4 },
  { "source": 1 , "target": 5 },
  { "source": 1 , "target": 6 },
  { "source": 0 , "target": 7 },
  { "source": 7 , "target": 8 },
  { "source": 7 , "target": 9 }
]
}

菜单我用的是jQuery插件,下载下来的,js/css代码就不展示了。

D3.js是一个强大的JavaScript库,用于数据可视化,其中的zoom缩放拖拽功能允许用户交互式地探索复杂的数据集。在D3的`d3.zoom()`函数中,你可以创建一个缩放行为,它可以应用于SVG、Canvas或任何支持CSS变换的元素上。 以下是D3 zoom缩放拖拽的基本实现步骤: 1. **创建Zoom行为**: ```javascript const zoom = d3.zoom() .scaleExtent([1, 10]) // 设置缩放范围 .on("zoom", zoomed); // 触发事件处理函数(zoomed) svg.append("g") .call(zoom); // 将zoom行为应用到SVG元素的子元素上 ``` 2. **定义zoomed函数**: 这个函数会在每次缩放事件后被调用,更新视的位置和比例: ```javascript function zoomed() { svg.select(".zoom-gROUP") .attr("transform", d3.event.transform); // 更新元素的transform属性 } ``` 3. **拖拽处理**: D3没有内置的拖拽功能,但你可以结合`d3.behavior.drag()`来添加拖拽。首先,创建一个可拖拽的元素,然后定义`dragged`函数来处理拖动事件: ```javascript const drag = d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended); element.call(drag); ``` 4. **处理开始、移动和结束事件**: ```javascript function dragstarted(d) { // 在开始拖动时设置初始位置 d3.event.sourceEvent.stopPropagation(); // 阻止默认的鼠标事件 } function dragged(d) { // 根据拖动更新元素位置 } function dragended(d) { // 拖动结束后可能需要更新状态或数据 } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值