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

你可能首先会想到,这很简单啊,是公司的时候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>

效果如图

d3根据数据绘制不同的形状的更多相关文章

  1. d3 根据数据绘制svg

    , , , , ]; var circles = svg.selectAll("circle") .data(dataset) .enter() .append("cir ...

  2. d3.js:数据可视化利器之快速入门

    hello,data! 在进入d3.js之前,我们先用一个小例子回顾一下将数据可视化的基本流程. 任务 用横向柱状图来直观显示以下数据: var data = [10,15,23,78,57,29,3 ...

  3. 如何将内存中的位图数据绘制在DC上

    假如你定义了一个位图类,里面包含位图头,位图信息头,调色板,位图数据.然后你按照位图的格式将位图文件读入你的类中,现在你知道了位图的全部信息了.主要信息包含在位图信息头里面,数据则在位图数据缓冲里面. ...

  4. Highcharts使用CSV格式数据绘制图表

    Highcharts使用CSV格式数据绘制图表 CSV(Comma-Separated Values,逗号分隔值文本格式)是採用逗号切割的纯文本数据.通常情况下.每一个数据之间使用逗号切割,几个相关数 ...

  5. linux环境安装nagiosgraph将nagios的性能数据绘制成动态图表?

    需求描述: 在安装完成nagios之后,比如有监控磁盘负载信息的,连接数的,进程数的,可以通过安装nagiosgraph软件, 将nagios的性能数据绘制成图表,可以看到一段时间内数据的变化 环境说 ...

  6. Highcharts使用表格数据绘制图表

    Highcharts使用表格数据绘制图表 在Highcharts中,同意用户使用网页中现有的表格数据作为数据来源,然后依据该数据来源绘制图表.对于一个典型的HTML表格.当中,第一列的数据会作为x轴刻 ...

  7. WPF 自定义的图表(适用大量数据绘制)下

    原文:WPF 自定义的图表(适用大量数据绘制)下 上一篇文章中讲了WPF中自定义绘制大量数据的图标,思路是先将其绘制在内存,然后一次性加载到界面,在后续的调试过程中,发现当数据量到达10W时,移动鼠标 ...

  8. WPF 自定义的图表(适用大量数据绘制)

    原文:WPF 自定义的图表(适用大量数据绘制) 在WPF中绘制图表比较简单,有很多的第三方控件,但是在绘制大量数据的时候,就显得有些吃力,即便是自己用StreamGeometry画也达不到理想的效果, ...

  9. MeteoInfoLab脚本示例:站点数据绘制等值线

    站点数据绘制等值线需要首先将站点数据插值为格点数据,MeteoInfo中提供了反距离权法(IDW)和cressman两个方法,其中IDW方法可以有插值半径的选项.这里示例读取一个MICAPS第一类数据 ...

随机推荐

  1. 去掉 Warning:$HADOOP_HOME is deprecated

    修改配置文件/etc/profile,增加环境变量HADOOP_HOME_WARN_SUPPRESS=1, 保存退出,再次启动hadoop,就不会出现警告信息了

  2. Eclipse dynamic web project 插件

    下载了Eclipse Oxygen   发现没有Dynamic web  Project 首先我们先了解下Dynamic  Web Project  If you want to create a c ...

  3. 深入浅出AQS之共享锁模式

    在了解了AQS独占锁模式以后,接下来再来看看共享锁的实现原理. 原文地址:http://www.jianshu.com/p/1161d33fc1d0 搞清楚AQS独占锁的实现原理之后,再看共享锁的实现 ...

  4. 常见sql技巧

    一.一些常见的SQL实践 (1)负向条件查询不能使用索引 select * from order where status!=0 and stauts!=1 not in/not exists都不是好 ...

  5. “==”与"equals(object)"的区别

    一.对于基本数据类型而言只能用“==”,不能用equals来进行比较,若使用equals来进行比较,则不能通过编译 二.在非字符串的对象的比较中: “==”与“equals()”比较的均是对象在堆内存 ...

  6. Qt中的坐标系统

    Qt使用统一的坐标系统来定位窗口部件的位置和大小. 以屏幕的左上角为原点即(0, 0)点,从左向右为x轴正向,从上向下为y轴正向,这整个屏幕的坐标系统就用来定位顶层窗口: 此外,窗口内部也有自己的坐标 ...

  7. 记一次Linux下JavaWeb环境的搭建

    今天重装了腾讯云VPS的系统,那么几乎所有运行环境都要重新部署了.过程不难懂,但是也比较繁琐,这次就写下来,方便他人也方便自己日后参考参考. 我采用的是JDK+Tomcat的形式来进行JavaWeb初 ...

  8. Musical Theme poj1743(后缀数组)

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 16757   Accepted: 5739 De ...

  9. python---time模块使用详解

    python中的time模块提供一些方法用来进行关于时间的操作,time模块中有以下方法可供使用: time() --- 返回当前时间的时间戳. 调用:time.time(),  可用于计算程序运行的 ...

  10. LCT学习笔记

    最近自学了一下LCT(Link-Cut-Tree),参考了Saramanda及Yang_Zhe等众多大神的论文博客,对LCT有了一个初步的认识,LCT是一种动态树,可以处理动态问题的算法.对于树分治中 ...