d3根据数据绘制不同的形状

   绘制力导向图的时候通常节点都是圆形,但也会遇到公司节点绘制成圆型,人绘制成方形的情况,那我们怎么依据数据绘制不同的形状。

   你可能首先会想到,这很简单啊,是公司的时候append circle,是人的时候append rect。但是append并没有提供回调也就是说我们不能这样做

node.append((data)=>{
   return data.type === 'person'  ? 'rect' : 'circle';  
});

  下面介绍两种方案:

 第一种,先append一个g然后根据数据设置不同的类名

var nodeGUpdate = this.nodeG
                  .selectAll('g')
                  .data(this.nodesData, (data) => data.id);

var nodeGEnter = nodeGUpdate.enter(); var nodeGExit = nodeGUpdate.exit(); // 更新 nodeGUpdate
.transition() .attr(
'class', (data) => {   return (data.hide && 'hide') || (data.nodeStatus < 0 && 'noActive') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'relativePerson'); }) nodeGEnter.append('g')
.attr(
'class', (data)=> {   return data.cateType === 2 ? 'person' : 'company'; })

然后依据类名append不同形状

添加矩形

this.nodeG
.selectAll('.person')
.append('rect')
.attr('class', (data) => {
  return (data.hide && '.hide') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'relativePerson');
 })
.attr('width', 20)
.attr('height', 20);

添加圆形

this.nodeG
.selectAll('.company')
.append('circle')
.attr('class', (data) => {
   return (data.hide && '.hide') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'relativePerson');
 })
.attr('r', 20);

最后效果

这有点尴尬,矩形是以它自身的左上角的为基点,所以你可能还需要根据象限进行平移。

上面这种思路是我从其它文章看来的,但出处忘了,但是由于还要将矩形的中心移到线的端点太麻烦,所以最终没有采用这种方法。

下面来讲另外一种方法

整体思路是统一append circle 但是当是人的时候填充圆形。就是可以想象append的这个circle相当于一个透明的画布,如果fill的值是颜色,那就是用这个颜色去填充这个圆。如果fill的是一个形状,就是用这个形状填充,由于背景是透明的,所以看起来好像append了其它形状上去。

首先在svg中定义一个矩形,defs简单来说就是一个容器,在这个元素里面你可以定义一些元素供你重复使用,例如箭头和这里定义的矩形。

这里有几个地方需要注意:

矩形 x,y的值

x,y是矩形的左上角相对于圆形的位置,设置x,y的值将矩形移至圆的中心,这样才能确保线的端点指向矩形的中心。

计算公式是 x=y = r  - 矩形宽度 / 2

确保矩形小于圆的内切正方形

打个比方,如果你透过一个圆形孔看一个较小的红色正方形,你会看到一个个完整的正方形,但如果正方形过大,你可能就只能看到一个红色的圆形了。

所以正方形宽度推导公式就是 width < 2*r / √2

<svg width="1000" height="1000">
  <defs>
     <pattern id="person" patternUnits="objectBoundingBox" width="1" height="1">
         <rect x="10" y="10" width="20" height="20" fill="#7FBBA1" stroke="#5CA083"/>
       </pattern>
    </defs>
 </svg>

确保圆是透明的

通俗点讲就是用于填充矩形的圆的样式中不能在设置fill和stroke了

 然后在绘制圆形的地方引用

nodeEnter
  .append('circle')
    .attr('class', (data) => {
       return (data.hide && '.hide') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'shape-relativePerson');
    })
    .attr('r', 20)
    .attr('fill', (data)=>{
        return data.cateType === 2 ? 'url(#person)' : '';
     })

下面是结果图

 

当然你可以扩展,例如如果是人的话绘制一个人的图片

<pattern id="person" patternUnits="objectBoundingBox" width="1" height="1">
  <image href={user} width="20" height="20" x="10" y="10"/>
</pattern>

效果如图

 

 

转载于:https://www.cnblogs.com/baize-q/p/7729847.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用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条边的拓扑图,节点和边的位置是随机生成的。运行代码后,可以看到一个简单的拓扑图,并且当鼠标悬停在节点上时,节点的颜色会变为红色。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值