D3.js 绘制带圆角的矩形 + 带箭头的指示线

目录

1. 添加带箭头的标线

2. 设置单个矩形盒子的宽高、偏移缩放效果

3. 添加 svg 元素,设置首次加载位置

4. 设置每个盒子纵横向的间距

5. 绘制矩形外层 box

6. 绘制矩形内层 box

7. 绘制矩形中的文字

8. 绘制括号和数字

9. 绘制带箭头的背景图片

10. 最终实现的效果



1. 添加带箭头的标线

  • 如何给 svg线条 添加箭头标记?
  • 给 svg线条 定义标记( 定义在 <defs> 中 ),从而为 <line> 或 <path> 添加箭头

  • <marker> 这个标签的作用?
  • <marker> 是标记的主体,<marker> 中的 <path> 是标记的图形(此处是箭头的路径)
  • 对于需要添加箭头的线段,设定其 marker-end 属性为 url(#arrow) 即可添加箭头
<defs>
  <!-- 添加带箭头的标线 -->
  <marker
    id="markerArrow"
    markerWidth="8"
    markerHeight="8"
    refx="2"
    refy="5"
    orient="auto"
  >
    <path d="M2,2 L2,8 L8,5 L2,2" style="fill: #61a8e0" />  
  </marker>
</defs>

2. 设置单个矩形盒子的宽高、偏移缩放效果

  // 盒子的宽高
  var boxWidth = 180,
  var boxHeight = 80;
  // 设置缩放和平移
  var zoom = d3.behavior.zoom()
    .scaleExtent([.1,1])
    .on('zoom', function(){
      svg.attr(
        "transform",
        "translate("
        + d3.event.translate
        + ") scale("
        + d3.event.scale
        + ")"
      );
  })
  // 偏移,防止第一次平移和缩放跳回原点
  .translate([150, 300]);

3. 添加 svg 元素,设置首次加载位置

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", "100%")
  .attr("height", $(window).height())
  .call(zoom)
  .append("g")
  // 设置首次加载位置
  .attr("transform", "translate(200, 300)");

4. 设置每个盒子纵横向的间距

  var tree = d3.layout.tree()
    // 节点间横向和纵向的距离
    .nodeSize([150, 300])
    .separation(function(){
      return 1;
    })
    .children(function(person){
      return person._parents;
    });

  d3.json('./data.json', function(error, json){
    if(error) {
      return console.error(error);
    }
    // 获取模块和连接关系的数据
    var nodes = tree.nodes(json),
        links = tree.links(nodes);
      // Style links (edges)
      svg.selectAll("path.link")
          .data(links)
          .enter().append("path")
          .attr("class", "link")
          .attr("d", elbow)

    // Style nodes
    var node = svg.selectAll("g.person")
        .data(nodes)
        .enter().append("g")
        .attr("class", "person")
        .attr("transform", function(d) { 
          return "translate(" + d.y + "," + d.x + ")"; 
        });
    // ...

5. 绘制矩形外层 box

  // 绘制外层box
  node.append("rect")
    .attr({
      x: -(boxWidth/2),
      y: function(d){
        if (d.depth === 0) { // 这里是绘制第一个盒子
          return -50;
        } else {
          return -((60 + 19* Math.ceil(d.name.length/7))/2)
        }
      },
      width: boxWidth,
      height: function(d){
          if (d.depth === 0) {
            return 100
          } else {
            return 60 + 19* Math.ceil(d.name.length/7)
          }
      },
      fill: '#fff', // 填充色
      "stroke-width": 1, // 外层盒子的边框粗细
      rx: function(d) { // 外层盒子的弯曲角度
          if (d.depth === 0) {
              return 50
          } else {
            return (60 + 19* Math.ceil(d.name.length/7)) / 2
          }
      }
    })
    .attr("stroke", function(d){ // 让外层盒子的颜色采取传入的数组的颜色
      return d.boxColor
    })
    .attr('class', 'rect-wrap');

6. 绘制矩形内层 box

  // 绘制内层box
  node.append("rect")
    .attr({
      x: -(boxWidth/2) +5,
      y: function(d){
        if (d.depth === 0) {
          return -45;
        } else {
          return -((60 + 19* Math.ceil(d.name.length/7) - 10)/2)
        }
      },
      width: boxWidth -10,
      height: function(d){
        if (d.depth === 0) {
          return 90;
        } else {
          return 60 + 19* Math.ceil(d.name.length/7) - 10
        }
      },
      rx: function(d){
          if (d.depth === 0) {
              return 45
          } else {
            return (60 + 19* Math.ceil(d.name.length/7) - 10) / 2
          }
      },
      fill: '#fff',
      "stroke-width": 3
    })
    .attr("stroke", function(d){
      return d.boxColor
    })
    .attr('class', 'rect-outside'); 

7. 绘制矩形中的文字

  • 盒子中的文字只能一行一行的写,并且要针对每一行设置单独的位置
  • 第一行文字:
  // 第一行标题
  node
    .append("text")
    .attr("dy", function (d) {
      if (d.depth === 0) {
        return -10;
      } else {
        // 截取到的第一行文字
        if (d.name.length / 10 <= 1) {
          return -5;
        } else if (d.name.length / 10 > 1 && d.name.length / 10 <= 2) {
          return -15;
        } else {
          return -25;
        }
      }
    })
    .attr("text-anchor", "middle")
    .attr("class", "label")
    .attr("stroke", function (d) {
      // 设置文字外围颜色
      return d.boxColor;
    })
    .attr("stroke-width", 0.2) // 设置颜色外围宽度
    .text(function (d) {
      return d.name.substring(0, 10); // 这样表示截取到第一行文字
    });
  • 第二行文字:
  node
    .append("text")
    .attr("dy", function (d) {
      if (d.name.length / 10 > 1 && d.name.length / 10 <= 2) {
        return 0;
      } else {
        return 10;
      }
    })
    .attr("text-anchor", "middle")
    .attr("class", "label")
    .attr("stroke", function (d) {
      return d.boxColor;
    })
    .attr("stroke-width", 0.2)
    .text(function (d) {
      return d.name.substring(10, 20); // 截取到第二行文字
    });
  • 第三行文字:
  node
    .append("text")
    .attr("dy", 20)
    .attr("text-anchor", "middle")
    .attr("class", "label")
    .attr("stroke", function (d) {
      return d.boxColor;
    })
    .attr("stroke-width", 0.1)
    .text(function (d) {
      return d.name.substring(20, d.name.length);
    });

8. 绘制括号和数字

  • 绘制第一个括号:
  node
    .append("text")
    .attr("dx", -20)
    .attr("dy", function (d) {
      if (d.depth === 0) {
        return 5;
      } else {
        if (d.name.length / 10 <= 1) {
          return 10;
        } else if (d.name.length / 10 > 1 && d.name.length / 10 <= 2) {
          return 15;
        } else {
          return 25;
        }
      }
    })
    .attr("class", "dividing-line")
    .attr("stroke", function (d) {
      return d.boxColor;
    })
    .attr("stroke-width", 0.5)
    .text(function (d) {
      return "(";
    });
  • 绘制第一个数字:
  .append("text")
  .attr("dx", -5)
  .attr("dy", function (d) {
      if (d.depth === 0) {
      return 5;
    } else {
      if (d.name.length / 10 <= 1) {
        return 10;
      } else if (d.name.length / 10 > 1 && d.name.length / 10 <= 2) {
        return 15;
      } else {
        return 25;
      }
    }
  })
  .attr("class", "num1")
  .attr("stroke", function (d) {
    return d.boxColor;
  })
  .attr("stroke-width", 0.5)
  .text(function (d) {
    return d.num1;
  });
  • 绘制第二个括号:
  node
    .append("text")
    .attr("dx", 13)
    .attr("dy", function (d) {
      if (d.depth === 0) {
        return 5;
      } else {
        if (d.name.length / 10 <= 1) {
          return 10;
        } else if (d.name.length / 10 > 1 && d.name.length / 10 <= 2) {
          return 15;
        } else {
          return 25;
        }
      }
    })
    .attr("class", "dividing-line")
    .attr("stroke", function (d) {
      return d.boxColor;
    })
    .attr("stroke-width", 0.5)
    .text(function (d) {
      return ")";
    });

9. 绘制带箭头的背景图片

    node
      .append("image")
      .attr("xlink:href", url2)
      .attr("x", -(boxWidth / 2) - 19)
      .attr("y", -9)
      .attr("fill", "#25723F")
      .attr("width", function (d) {
        if (d.depth === 0) {
          return 0;
        } else {
          return 30;
        }
      })
      .attr("height", 18); // 设置箭头的大小

10. 最终实现的效果

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
要使用D3.js绘制拓扑图,可以按以下步骤进行操作: 1. 定义数据结构:拓扑图通常由节点和边组成,需要定义节点和边的数据结构。 2. 创建SVG容器:使用D3.js创建SVG容器,设置宽度和高度。 3. 绘制节点:使用D3.js绘制节点,可以根据节点的属性设置节点的大小、形状、颜色等。 4. 绘制边:使用D3.js绘制边,可以根据边的属性设置边的粗细、颜色等。 5. 添加交互:可以为节点和边添加交互效果,例如鼠标悬停、点击等。 以下是一个简单的示例代码: ```javascript // 定义数据结构 var nodes = [{id: 1, name: 'Node 1'}, {id: 2, name: 'Node 2'}, {id: 3, name: 'Node 3'}]; var links = [{source: 1, target: 2}, {source: 2, target: 3}, {source: 3, target: 1}]; // 创建SVG容器 var svg = d3.select('body').append('svg') .attr('width', 400) .attr('height', 400); // 绘制节点 var node = svg.selectAll('.node') .data(nodes) .enter().append('circle') .attr('class', 'node') .attr('r', 20) .attr('cx', function(d) { return Math.random() * 400; }) .attr('cy', function(d) { return Math.random() * 400; }) .style('fill', 'blue'); // 绘制边 var link = svg.selectAll('.link') .data(links) .enter().append('line') .attr('class', 'link') .attr('x1', function(d) { return node.filter(function(n) { return n.id === d.source; }).attr('cx'); }) .attr('y1', function(d) { return node.filter(function(n) { return n.id === d.source; }).attr('cy'); }) .attr('x2', function(d) { return node.filter(function(n) { return n.id === d.target; }).attr('cx'); }) .attr('y2', function(d) { return node.filter(function(n) { return n.id === d.target; }).attr('cy'); }) .style('stroke', 'black') .style('stroke-width', 2); // 添加交互 node.on('mouseover', function() { d3.select(this).style('fill', 'red'); }).on('mouseout', function() { d3.select(this).style('fill', 'blue'); }); ``` 这段代码创建了一个包含3个节点和3条边的拓扑图,节点和边的位置是随机生成的。运行代码后,可以看到一个简单的拓扑图,并且当鼠标悬停在节点上时,节点的颜色会变为红色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lyrelion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值