今天遇到一个在曲线路径上标识文本标记的问题,找到一个比较好的解决思路,在这里分享下:

使用d3建立的Force Layout,加上自定义的箭头形状,将多条连接线线改成弧线(https://www.cnblogs.com/webhmy/p/10906268.html)。现需沿弧线加上文字

var edgelabels = svg.selectAll(".edgelabel")
.data(dataset.edges)
.enter()
.append('text')
.attr(...); edgelabels.append('textPath')
.attr('xlink:href',function(d,i) {return '#edgepath'+i})
.text(function(d,i){return 'label '+i});

使用text元素定义文字,然后为text元素添加textPath子元素,通过指定textPath的属性,将文字的定位与其他路径关联起来。定义弧线路径需要添加id属性

var path = svg.append('svg:g').selectAll('path')
.data(force.links())
.enter().append('svg:path')
.attr('class', function(d) { return 'link ' + d.type; })
.attr(...)
.attr('id', function(d,i){return 'edgepath'+i;});

问题出在SVG文字路径的方向性上。注意图中上下颠倒的"68万",因为它所从属的有向弧是自右向左从『渠道』连向『资金』,文字也跟着上下左右颠倒了。

要想让文字的方向正过来,弧的方向需要人为的反过来。这本身并不困难,只要在指定弧的路径的时候检查起点和终点的x值,始终把较小的一方作为起点就好。

然而如果直接这样做,图中的箭头也会反过来,图的含义就变了

先回顾一下箭头的画法,是定义了一个名为"end"的小三角形标记(marker),然后将这个marker指定为弧的结束标记("marker-end"属性):

// build the arrow.
svg.append("svg:defs").selectAll("marker")
.data(["end"])
.enter().append("svg:marker")
.attr("id", String)
.attr(...)
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5"); // add the links and the arrows
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", "url(#end)");

现在因为必须把弧反过来画,就得在起点画一个形状相反的marker,来冒充原来的end marker。所以稍微修改一下代码,增加一个新的marker:

// build the arrows
var defs = svg.append('svg:defs');
defs.append('svg:marker')
.attr('id', 'end')
.attr(...)
.append('svg:path')
.attr('d', 'M0,-5L10,0L0,5'); defs.append('svg:marker')
.attr('id', 'start')
.attr(...)
.append('svg:path')
.attr('d', 'M0,0L10,-5L10,5');

因为d3的Force Layout自带进场动画,弧的开始和结束点在动画进行中会一直变化,需要动态决定绘制方向和使用marker-start还是marker-end属性,就不能再像例子中那样直接静态指定,而是要放到负责动画的tick()函数中:

function tick() {
path.attr('d', function(d) {
var x1 = ..., y1 = ...,
x2 = ..., y2 = ...,
r = ...;
if (x1 < x2) {
return 'M' +
x1 + ',' + y1 + 'A' +
r + ',' + r + ' 0 0,1 ' +
x2 + ',' + y2;
} else {
return 'M' +
x2 + ',' + y2 + 'A' +
r + ',' + r + ' 0 0,0 ' +
x1 + ',' + y1;
}
})
.attr('marker-end', function(d) {
if (d.source.x < d.target.x) {
return 'url(#end)';
}
return '';
})
.attr('marker-start', function(d) {
if (d.source.x >= d.target.x) {
return 'url(#start)';
}
return '';
});
...
}

这样得到的结果是

文字的上下左右方向正确了。但对所有伪装成功的弧而言,文字都被标记在了弧的内侧。这是因为文字默认的定位锚点(anchor point)是按基线(baseline)算起,因此始终会在弧的上方。有了上面的经验,如法炮制,在tick()函数中加上一段:

function tick() {
path.attr('d', function(d) {
...
})
.attr('marker-end', function(d) {
...
})
.attr('marker-start', function(d) {
...
}); edgelabels.attr('dominant-baseline', function(d) {
if (d.source.x < d.target.x) {
return 'text-after-edge';
}
return 'text-before-edge';
});
...
}

总结

这里的主要思路是,文字是跟随线的方向。如果是反向的弧线,字会颠倒,为了使文字显示正确,这里使用了一个hack

对箭头做了个处理,每条线都加了开始和结束的箭头

根据数据做驱动,当源数据的x坐标小于目标数据的x坐标的时候,显示end箭头

当源数据的x坐标大于目标数据的x坐标的时候,显示start箭头

这个思路很好的解决了我的问题,因此分享下,本文转自 https://zhuanlan.zhihu.com/p/20706807

D3力布图绘制--在曲线路径上添加文本标记的更多相关文章

  1. D3力布图绘制--节点跑掉,单曲线弯曲问题记录

    D3力布图绘制中遇到的交互问题,频繁操作数据后,会出现节点跑掉和单曲线弯曲的问题 问题描述 在id指向都正常的情况下出现以下2种状况: 单曲线弯曲 节点跑掉 经排查,是数据重复导致的问题 线条也是一样 ...

  2. D3力布图绘制--节点自己连自己的实现

    案例分析 先看下实现的效果图 实现方法 本篇是在之前写的博文 D3力布图绘制--节点间的多条关系连接线的方法 基础上加修改的,这里放上修改的代码,其他的一样 // DATA var nodes = [ ...

  3. D3力布图绘制--节点间的多条关系连接线的方法(转)

    在项目中遇到这样的场景,在使用D3.js绘制力布图的过程中,需要在2个节点间绘制多条连接线,找到一个不错的算法,在此分享下. 效果图: HTML中要连接 <!DOCTYPE html> & ...

  4. D3力布图绘制--基本方法

    本文主要结合案例记录使用D3.js绘制力布图的基本方法 样例显示 基本配置 this.force = d3.layout .force() .size([this.width, this.height ...

  5. d3力导图绘制节点间多条关系平行线的方法

    之前用d3做了多条线之间的绘图是曲线表示的,现在产品要求改成平行线的样式,经过在网上的调研和自己的尝试,实践出一个可用的方法,分享给大家,先展示下结果: 事先声明,本方法是在以下参考网站上进行的结合和 ...

  6. d3力导向图聚焦

    效果描述 双击节点,节点以及节点一度关联的节点保持高亮状态,其余节点变灰,半径变小,文字消失,并且向内收缩. 效果展示 正常状态 聚焦效果 关键代码 节点变化 激活节点保持高亮的样式,其余节点应用no ...

  7. Vue和d3.js(v4)力导向图force结合使用,v3版本升级v4【一】

    前段时间因为参与项目涉密,所以一直没有更新博客,有些博友给我私信或者留言要部分博文的源码,因为我的电脑更换,demo的源码没有备份 所以无法提供.大家可针对具体问题问我,有空我定会回复的.另外转发文章 ...

  8. SpringBoot图文教程「概念+案例 思维导图」「基础篇上」

    有天上飞的概念,就要有落地的实现 概念+代码实现是本文的特点,教程将涵盖完整的图文教程,代码案例 每个知识点配套自测面试题,学完技术自我测试 本文初学向,所以希望文中所有的代码案例都能敲一遍 大哥大姐 ...

  9. D3.js系列——布局:饼状图和力导向图

    一.饼状图 在布局的应用中,最简单的就是饼状图. 1.数据 有如下数据,需要可视化: , , , , ]; 这样的值是不能直接绘图的.例如绘制饼状图的一个部分,需要知道一段弧的起始角度和终止角度,这些 ...

随机推荐

  1. springcloud微服务多节点高性能、高可用、高并发部署

    1. 共有三个服务 discovery服务,domain服务,gateway服务. discovery服务是用来注册其他服务的,作为服务治理用. domain服务是主业务服务. gateway服务是所 ...

  2. ABAP对象-面向对象(转)

    转自:https://www.jianshu.com/p/f847c8f71438 1 面向对象基础 不多赘述何为对象与类.简单回顾一下在面向对象特性. 封装 限定内部资源的可见性 多态 相同名称的方 ...

  3. hello tensorflow,我的第一个tensorflow程序

    上代码: import tensorflow as tf if __name__=='__main__': g = tf.Graph() # add ops to the user created g ...

  4. SQLPrompt8.2 安装之后找不到激活入口

    如果你发现是这样的,找不到像其他人说的serial number这个选项,不要惊慌.. 首先你得先断网,然后再打开sql客户端,点击Manage License ,然后你会看到 activate 这个 ...

  5. 100款机械CAD图纸,想要出图快,勤练是最有效的方式之一!

    提升CAD出图效率最有效的方式就是勤加练习,所以跟着小匠每天练习3个,30天把这100个常用的CAD机械图纸练完,再看你的出图效率!贵在坚持! 100个机械CAD图纸,请收好

  6. DDCTF 2019 部分WP

    WEB 滴~ http://117.51.150.246/index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09 观察链接可发现jpg的值是文件名转hex再bas ...

  7. 利用InsertStatusValueRequest消息为新增的statuscode设定指定值(Value)

    我是微软Dynamcis 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  8. swift个人总结

    最近iOS10 已经开始正式使用,研究使用了swift3.0,将一些总结记录于此,以便以后查阅.持续更新中. swift中一般将一些功能相近的方法写在同一个延展中,便于代码的规范,找起来也方便.区别o ...

  9. PL/SQL编写的SQL语句插入SqlPlus时,报错 PLS-00302

    最近刚开始用PL/SQL,然后发现写SQL语句时,运行的时候,会对表中的字段报错. 好像是对字段的使用有问题 原来写的错误代码大概像这样 DECLARE xuehao XSB.id% TYPE; BE ...

  10. 【JavaWeb】JSTL标签库

    JSTL标签库 JSTL标准标签库: JSTL用于简化JSP开发,提高代码的可读性与可维护性: JSTL由SUN(Oracle)定义规范,由Apache Tomcat团队实现: 引用JSTL核心库 核 ...