欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

D3可视化:(1)初次见面,SVG与D3的魅力

发布时间:2025/4/16 编程问答 39 豆豆
生活随笔 收集整理的这篇文章主要介绍了 D3可视化:(1)初次见面,SVG与D3的魅力 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

D3.js是一个基于HTML/SVG/CSS的数据可视化库,是领域内非常强大的存在了。

今后会在工作使用,也因此开始了自学之旅。学习过程中,我主要通过Curran Kelleher老师的系列教程进行学习,这个笔记用于学习、整理和分享,陆续学习、更新和记录中....

原文链接

学习目的:

  • 熟悉和认识D3.js
  • 练习使用SVG画图,熟悉操作
  • 练习D3.js的基本函数和操作

完成效果图: 在线demo

D3初印象

选择集

D3是实现数据可视化,仍然离不开传统DOM的选择和操作,也因此,D3提供了类似Jquery的DOM操作指令:

  • d3.select:选择第一个指定元素
  • d3.selectAll : 选择所有的元素
const svg = d3.select('svg') //选择svg const p = svg.selectAll('p') //选择svg下所有的p标签复制代码

当然,可以使用#id 以及 .class 对id和类进行选择

查看状态

d3.select和d3.selectAll返回的都是选择集,添加、删除以及修改都需要用到选择集,查看状态有三个函数可以使用:

  • selection.empty() 选择集为空,返回true,否则返回false
  • selection.node() 返回第一个非空元素,如果选择集为空,返回null
  • selection.size() 返回选择集中的元素个数

设定和获取属性

使用select或selectAll选择后,可以通过attr获取和设定属性,可以使用append方法添加元素

const svg = select('svg'); svg.append('circle').attr('r','30')复制代码

使用D3和SVG画图

html文件

<html lang="en"> <head><title>Smile face with d3</title> </head> <body><svg width="960" height="500"></svg><script src="https://d3js.org/d3.v5.min.js"></script><script src="index.js"></script> </body> </html> 复制代码

主要内容通过index.js实现:

第一步:通过d3选择SVG,使用circle构建轮廓

const svg = d3.select('svg'); const height = +svg.attr('height'); const width = +svg.attr('width'); svg.append('circle').attr('r',height / 2).attr('cx', width / 2).attr('cy', height / 2).attr('fill', 'yellow').attr('stroke','black')const leftEye = svg.append('circle').attr('r', 30).attr('cx', width / 2 - 100).attr('cy', height / 2 - 80).attr('fill', 'black')const rightEye = svg.append('circle').attr('r', 30).attr('cx', width / 2 + 100).attr('cy', height / 2 - 80).attr('fill', 'black') 复制代码

要点:

  • 通过attr获取的属性是string类型的,通过parseFloat或者+转换为number类型
  • 对圆形circle的属性cx cy等,使用变量作为其大小设置的值,而不用一个数字,方便日后的维护
  • leftEye和RightEye用类似的方法,创造出来,并将眼睛放置在合适的位置。

代码优化

1)可以发现,对三个圆圆心的操作cx和cy出现了多次,而作用也仅仅是为了将圆放在中心。因此,可以通过SVG中的<g>来分组来实现一次性操作。

const g = svg.append('g').attr('transform',`translate(${ width / 2}, ${ height / 2})`)//这样,在画圆的时候,就可以去掉对其圆心的操作,因为默认的位置就在中心了 const circle = g.append('circle').attr('r',height / 2).attr('fill', 'yellow').attr('stroke','black') 复制代码

2)同样的,对于眼睛的操作,也有点繁琐,可以通过变量和分组,提高代码的可维护性能。

const eyeSpacing = 100; const eyeYoffset = -80 const eyeRadius = 30;const eyesG = g.append('g').attr('transform', `translate(0, ${eyeYoffset})`);const leftEye = eyesG.append('circle').attr('r', eyeRadius).attr('cx', - eyeSpacing)const rightEye = eyesG.append('circle').attr('r', eyeRadius).attr('cx', + eyeSpacing) 复制代码

第二步 嘴巴

嘴巴实际上是一个弧线,使用SVG中的path进行绘制。熟悉path的,当然可以直接给参数进行绘制,但是d3对圆弧有更好的支持,可以使用d3.arc函数,方便的绘制圆弧。

arc函数

根据官方的API手册,函数的使用方法如下:

var arc = d3.arc();arc({innerRadius: 0,outerRadius: 100,startAngle: 0,endAngle: Math.PI / 2 }); // "M0,-100A100,100,0,0,1,100,0L0,0Z" 复制代码

其中,innerRadius是内圆半径,outerRadius是外圆半径,startAngle和endAngle分别是开始和结束的弧度(完整的圆是0~2PI)

笑脸的实现

根据以上内容,代码如下:

const mouth = g.append('path').attr('d',d3.arc()({innerRadius: 150,outerRadius: 170,startAngle: Math.PI /2,endAngle: Math.PI * 3 / 2})) 复制代码

眉毛

眉毛用简单的长方形来代替,也就是svg中的<rect>,使用前文的编程风格,将眉毛归为一个group,并将位置设定。

const eyebrowWidth = 50; const eyebrowHeight = 10; const eyebrowYoffset = -150; const BrowG = g.append('g').attr('transform',`translate(${-eyebrowWidth / 2},${eyebrowYoffset})`);const leftEyebrow = BrowG.append('rect').attr('width',eyebrowWidth).attr('height',eyebrowHeight).attr('x',-eyeSpacing)const rightEyebrow = BrowG.append('rect').attr('width', eyebrowWidth).attr('height', eyebrowHeight).attr('x', eyeSpacing) 复制代码

加入动画

使用transition函数设置眉毛的动画,让笑脸动起来

const BrowG = g.append('g').attr('transform',`translate(${-eyebrowWidth / 2},${eyebrowYoffset})`); BrowG.transition().duration(2000).attr('transform', `translate(${-eyebrowWidth / 2},${eyebrowYoffset - 50})`).transition().duration(2000).attr('transform', `translate(${-eyebrowWidth / 2},${eyebrowYoffset})`).duration(2000)复制代码

注意点:

  • transition函数要对号入座,即如果加在了<g>上,对应的增加的属性动画应该在transform上; 如果动画在<rect>上,动画应该在y属性上。
  • 添加动画不能在append函数之后连接,比如BrowG.append('g').attr(...).transition()是不行的。因为过度动画无法绑定在append的元素上,需要分别操作。

完整代码

code downlaod here

const svg = d3.select('svg'); const height = +svg.attr('height'); const width = +svg.attr('width'); const g = svg.append('g').attr('transform',`translate(${ width / 2}, ${ height / 2})`)const circle = g.append('circle').attr('r',height / 2).attr('fill', 'yellow').attr('stroke','black')const eyeSpacing = 100; const eyeYoffset = -80 const eyeRadius = 30; const eyebrowWidth = 50; const eyebrowHeight = 10; const eyebrowYoffset = -150;const eyesG = g.append('g').attr('transform', `translate(0, ${eyeYoffset})`);const leftEye = eyesG.append('circle').attr('r', eyeRadius).attr('cx', - eyeSpacing)const rightEye = eyesG.append('circle').attr('r', eyeRadius).attr('cx', + eyeSpacing)const mouth = g.append('path').attr('d',d3.arc()({innerRadius: 150,outerRadius: 170,startAngle: Math.PI /2,endAngle: Math.PI * 3 / 2}))const BrowG = g.append('g').attr('transform',`translate(${-eyebrowWidth / 2},${eyebrowYoffset})`); BrowG.transition().duration(2000).attr('transform', `translate(${-eyebrowWidth / 2},${eyebrowYoffset - 50})`).transition().duration(2000).attr('transform', `translate(${-eyebrowWidth / 2},${eyebrowYoffset})`).duration(2000)const leftEyebrow = BrowG.append('rect').attr('width',eyebrowWidth).attr('height',eyebrowHeight).attr('x',-eyeSpacing)const rightEyebrow = BrowG.append('rect').attr('width', eyebrowWidth).attr('height', eyebrowHeight).attr('x', eyeSpacing)复制代码

总结

以上是生活随笔为你收集整理的D3可视化:(1)初次见面,SVG与D3的魅力的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。