网站首页 > 博客文章 正文
创建vue项目和依赖
首先创建一个vue的单页应用,为了能简便的设置项目样式,引入了bootstrap,项目使用的力向导图,主要依赖于d3.js,添加d3的依赖引用。
npm create vue@latest
npm install bootstrap
npm install d3
引入bootstrap依赖后,需要把对应的css路径设置到main.js上
import 'bootstrap/dist/css/bootstrap.css'
d3的不同版本的脚本使用有一定区别,当前版本是7.8.5
准备数据
需要准备一个节点数组和一个链接的边数组
nodes中的id是唯一标记,name是节点需要显示的名称
links中的source是线条开始的节点,其中target是线条结束的节点,name是线条上显示的名称,id是线条的唯一id
let nodes=[
{"id":1,"name":"a"},
{"id":2,"name":"b"},
{"id":3,"name":"c"},
{"id":4,"name":"d"},
{"id":5,"name":"e"},
{"id":6,"name":"f"}
]
let links=[
{"id":1,"source":1,"target":2,"name":"link1"},
{"id":2,"source":1,"target":3,"name":"link2"},
{"id":3,"source":1,"target":4,"name":"link3"},
{"id":4,"source":1,"target":5,"name":"link4"},
{"id":5,"source":1,"target":6,"name":"link5"},
{"id":6,"source":2,"target":6,"name":"link6"}
]
d3在项目中的实践应用
创建页面svg元素
在页面上写一个svg,注意必须包含id,后面会用到
<svg id="svg" style="width:100%;height:900"></svg>
准备d3的配色方案
获取d3的配色方案,注意NodeLabels是一个数组,可以根据自己的节点类型进行设计
var NodeLabels = ['A', 'B', 'C', 'D', "E", "F", "G"]
var color = d3.scaleOrdinal().domain(NodeLabels).range(d3.schemeTableau10)
初始化布局
布局中需要使用nodes和links数组,注意,最后一行的ticked方法还没有写,后面写
let simulation=d3.forceSimulation(nodes)
.force('charge', d3.forceManyBody().strength(-3000))
.force('center', d3.forceCenter(width / 2, height / 2))
.force('x', d3.forceX(width / 2).strength(1))
.force('y', d3.forceY(height / 2).strength(1))
.force('link', d3.forceLink(links).id(function (d) { return d.id }).distance(0))
.on('tick', ticked)
获取svg容器
其中width是svg的宽,height是svg的高。如果设定的固定高度,可以直接写死,
let svg = d3.select('#svg').attr('width', width).attr('height', height)
let container = svg.append('g')
如果是填充的高度/宽度可以通过clientWidth/clientHeight获取具体的值
let width=document.getElementById("svg").clientWidth
let height=document.getElementById("svg").clientHeight
设置nodes节点
通过下面的代码,会对nodes数组中的每个对象创建一个节点。节点的类型是一个圆(circle),半径是15,通过nodes对象的名称设置不同的颜色。
let node = container.append('g').attr('class', 'nodes')
.selectAll('g')
.data(nodes)
.enter()
.append('circle')
.attr("id",d=>d.id)
.attr('r', 15)
.attr('fill', function (d) { return color(d.name) })
有了节点后,就可以设置 ticked方法了
function ticked () {
node.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')'
})
}
到这就可以运行起来看效果了,到这所有的节点就能显示出来了
设置连接线的边
看到节点后,下面记录设置连接线
设置链接线,用到了links数组,设置的线颜色是红色,线宽度是1
let link = container.append('g').attr('class', 'links')
.selectAll('line')
.data(links)
.enter()
.append('line')
.attr('stroke', d=>{
return "red"
})
.attr('stroke-width', '1px')
修改上面的ticked方法,增加设置线在svg上的位置
function ticked () {
node.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')'
})
link.attr('x1', function (d) { return (d.source.x) })
.attr('y1', function (d) { return (d.source.y) })
.attr('x2', function (d) { return (d.target.x) })
.attr('y2', function (d) { return (d.target.y) })
}
再次运行,就能看到节点和连接线了
设置节点文字
在节点上显示对应节点的名字
虽然显示了各种节点,但是不知道具体那个节点什么含义,就要使用到节点的名称(name属性),
通过.text属性设置具体的显示字段,通过fill设置字体颜色,通过x,y分别设置文字的位置
let nodeword = container.append('g').attr('class', 'labelNodes')
.selectAll('text')
.data(nodes)
.enter()
.append('text')
.text(function (d, i) { return d.name })
.style('fill', '#555')
.style('font-family', 'Arial')
.attr("text-anchor", "middle")
.style('font-size', 16)
.style('pointer-events', 'none')
.attr('x', function (d) {
return d.x;
})
.attr('y', d => d.y)
再次修改ticked方法,显示节点的名称
把下面的代码放入ticked方法中
nodeword.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')'
})
再次运行的效果图,如下图
设置连接线文字
如果连接线的边也有具体的含义,也可以设置边的文字描述
使用text属性设置具体需要显示的字段
let linkword = container.append('g').attr('class', 'labelText')
.selectAll('text')
.data(links)
.enter()
.append('text')
.text(function (d, i) { return d.name })
.style('fill', '#555')
.style('font-family', 'Arial')
.attr("text-anchor", "middle")
.style('font-size', 10)
.style('pointer-events', 'none')
再次修改ticked方法,设置连接线的边的文字位置
把下面的代码,直接放到ticked方法中即可
linkword.attr('transform', d => {
let x = Math.min(d.source.x, d.target.x) + Math.abs(d.source.x - d.target.x) / 2
let y = Math.min(d.source.y, d.target.y) + Math.abs(d.source.y - d.target.y) / 2 - 1
let tanA = Math.abs(d.source.y - d.target.y) / Math.abs(d.source.x - d.target.x)
let angle = Math.atan(tanA) / Math.PI * 180
if (d.source.x > d.target.x) {
if (d.source.y <= d.target.y) {
angle = -angle
}
} else if (d.source.y > d.target.y) {
angle = -angle
}
return 'translate(' + x + ',' + y + ')' + 'rotate(' + angle + ')'
})
重新运行的效果如下图:
设置svg的缩放
其中缩放范围是0.1到4倍大小。注意d3.js的5版本和7版本的使用方式不一样
svg.call(
d3.zoom()
.scaleExtent([.1, 4])
.on('zoom', function () { container.attr('transform', d3.zoomTransform(this)) })
)
设置svg图的节点拖拽功能
默认情况下所有的节点是不能拖动的,如果项节点可以随意拖动,可以设置drag方法,这样节点就可以随意拖动了
function dragstarted (event) {
event.sourceEvent.stopPropagation()
if (!event.active) simulation.alphaTarget(0.3).restart()
event.subject.fx = event.subject.x
event.subject.fy = event.subject.y
}
function dragged (event) {
event.subject.fx = event.x
event.subject.fy = event.y
}
function dragended (event) {
if (!event.active) simulation.alphaTarget(0)
event.subject.fx = null
event.subject.fy = null
}
node.call(
d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended)
)
删除svg上的所有的节点
如果在当前svg上需要进行多次操作,可以在每次开始前删除所有的svg元素
d3.select('svg').selectAll('*').remove();
效果图
写在最后
现在网上有很多d3的版本5的代码,但是在实际使用的时候总会出现各种莫名其妙的错误。
由于vue已经设计到vue3了,很多以前的vue项目都需要node17及以下版本才能使用。如果使用最新的nodejs则会出现各种莫名其妙的错误,根本解决不完
按照官方的要求,重新写了一份。花费了很多天的时间,也走了很多的弯路,最终结果还是好的。
猜你喜欢
- 2024-11-25 又一个布局利器,CSS 伪类 :placeholder-shown
- 2024-11-25 值得收藏的CSS小技巧
- 2024-11-25 尤娜v1.2.2内置函数用法-Part II(分页函数)
- 2024-11-25 总结7个工作中常用的css3案例,带你了解冷门却实用的特性
- 2024-11-25 带你手写一个轮播图之HTML结构和CSS布局设计
- 2024-11-25 稍微整理了几个经常在H5移动端开发遇到的东西
- 2024-11-25 七爪源码:如何使用 vanilla JS & CSS 创建滚动到顶部按钮
- 2024-11-25 吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【上】
- 2024-11-25 3个超秀的 Vue 卡片翻动组件Vue-Card-Slide
- 2024-11-25 揭秘前端无刷新提交数据的黑科技 - React Server Actions深度解析
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)