D3.js 基础笔记

内容出自:FreeCodeCamp

D3 或 D3.js 表示数据驱动文档。它是一个用于在浏览器中创建动态和交互式数据视觉化的 JavaScript 库。1

学习资源

基础操作

修改元素

  • select()
    • 功能:从文档中选择一个元素。
    • 参数:它接受你想要选择的元素的名字作为参数,并返回文档中第一个与名字匹配的 HTML 节点。
  • selectAll()
    • 选择一组元素。 并以 HTML 节点数组的形式返回该文本中所有匹配所输入字符串的对象
  • append()
    • 功能:将 HTML 节点附加到选定项目,并返回该节点的句柄。
    • 参数:接收你希望添加到文档中的元素
  • text()
    • 功能:设置所选节点的文本,也可以获取当前文本。 也可以用来添加标签
    • 参数:字符串或者回调函数
js
const anchor = d3.select('a')

在 D3 中可以串联多个方法,连续执行一系列操作。->[[function chaining|链式调用]]

使用数据

d3-selection

  • data()
    • 将元素与数据绑定
    • 不需要写 for 循环或者用 forEach() 迭代数据集中的对象。 data() 方法会解析数据集,任何链接在 data() 后面的方法都会为数据集中的每个对象运行一次。
    • 可以使用方括号的方式,如 d[0],来访问数组中的值。
  • enter():获取需要插入的选择集(数据个数大于元素个数)的占位符.

当 enter() 和 data() 方法一起使用时,它把从页面中选择的元素和数据集中的元素作比较。 如果页面中选择的元素较少则创建缺少的元素。

可以理解为管理仓库的,选择的元素是货架,数据是货,如果货架不够了,就再补几个货架,如果多了就不管

html
<body>
<ul></ul>
<script>
const dataset = ['a', 'b', 'c']
d3.select('ul').selectAll('li').data(dataset).enter().append('li').text('New item')
</script>
</body>

使用动态数据

text 中设置回调处理数据如:

  • d3.json(): 从指定的 input URL 获取 JSON 文件。如果指定了 init 则会将其传递给底层的 fetch 方法
html
<body>
<script>
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9]
d3.select('body')
.selectAll('h2')
.data(dataset)
.enter()
.append('h2')
.text(d => d + ' USD')
</script>
</body>

给元素添加内联样式

  • style()
    • 功能:在动态元素上添加内联 CSS 样式
    • 参数:以用逗号分隔的键值对作为参数
js
selection.style('color', 'blue')
//用回调过滤
selection.style('color', d => {
return d < 20 ? 'red' : 'green'
})
// 动态设置样式
selection.style('height', d => d + 'px') // 动态设置高度

添加 Class

  • attr()
    • 功能:可以给元素添加任何 HTML 属性,包括 class 名称。
    • 参数:
      • attr() 方法和 style() 的使用方法一样。 它使用逗号分隔值,并且可以使用回调函数
      • 可接收一个回调函数来动态设置属性。 这个回调函数有两个参数,一个是数据点本身(通常是 d),另一个是该数据点在数组中的下标 i, 这个参数是可选的
    • 当需要添加 class 时,class 参数保持不变,只有 container 参数会发生变化。
js
selection.attr('class', 'container')
// 回调
selection.attr('property', (d, i) => {})
// 比如改变间距
svg
.selectAll('rect')
.data(dataset)
.enter()
.append('rect')
.attr('x', (d, i) => {
return i * 30 //改变间距
})
.attr('y', (d, i) => {
return d * 3 //改变高度
})
//悬停效果
.attr('class', 'bar')

标签

  • 和 rect 元素类似,text 元素也需要 x 和 y 属性来指定其放置在 SVG 画布上的位置, 它也需要能够获取数据来显示数据值。
  • 标签样式
    • fill 属性为 text 节点设置文本颜色
    • style() 方法设置其它样式的 CSS 规则,例如 font-family 或 font-size。
js
//添加标签
svg
.selectAll('text')
.data(dataset)
.enter()
.append('text')
.attr('x', (d, i) => i * 30)
.attr('y', (d, i) => h - 3 * d - 3) // 高三个单位是减
.text(d => d)
// 添加样式
.attr('fill', 'red')
.style('font-size', '25px')
//悬停效果
.attr('class', 'bar')
/** css中
.bar:hover {
fill: brown;
}
**/

添加工具提示 tooltip

  • 当用户在一个对象上悬停时,提示框可以显示关于这个对象更多的信息
  1. title
js
svg
.selectAll('rect')
.data(dataset)
.enter()
.append('rect')
.attr('x', (d, i) => i * 30)
.attr('y', (d, i) => h - 3 * d)
.attr('width', 25)
.attr('height', (d, i) => d * 3)
// 每个 rect 节点下附加 title 元素。 然后用回调函数调用 text() 方法使它的文本显示数据值。
.append('title')
.text(d => d)

SVG

  • 坐标系:坐标轴的原点在左上角。 x 坐标为 0 将图形放在 SVG 区域的左边缘, y 坐标为 0 将图形放在 SVG 区域的上边缘。 x 值增大矩形将向右移动, y 值增大矩形将向下移动。

创建 SVG

js
//创建svg
selection.append('svg')

反转 SVG 元素

  • 为了使条形图向上,需要改变 y 坐标计算的方式

SVG 区域的高度为 100。 如果在集合中一个数据点的值为 0,那么条形将从 SVG 区域的最底端开始(而不是顶端)。 为此,y 坐标的值应为 100。 如果数据点的值为 1,你将从 y 坐标为 100 开始来将这个条形设置在底端, 然后需要考虑该条形的高度为 1,所以最终的 y 坐标将是 99。

(高度从下面开始计算,坐标轴从上面开始)

  • y 坐标为 y = heightOfSVG - heightOfBar 会将条形图向上放置。
  • 通常,关系是 y = h - m * d,其中 m 是缩放数据点的常数。

更改 SVG 元素的颜色

  • 在 SVG 中, rect 图形用 fill 属性着色。 它支持十六进制代码、颜色名称、rgb 值以及更复杂的选项,比如渐变和透明。
js
svg
.selectAll('rect')
.data(dataset)
.enter()
.append('rect')
.attr('x', (d, i) => i * 30)
.attr('y', (d, i) => h - 3 * d)
.attr('width', 25)
.attr('height', (d, i) => 3 * d)
//将所有条形图的 fill 设置为海军蓝。
.attr('fill', 'navy')

SVG 图形

  • SVG 支持多种图形,比如矩形和圆形, 并用它们来显示数据。

矩形

SVG 的 rect 有四个属性。 x 和 y 坐标指定图形放在 svg 区域的位置, height 和 width 指定图形大小

js
const svg = d3
.select('body')
.append('svg')
.attr('width', w)
.attr('height', h)
.append('rect') //rect矩形
.attr('width', 25)
.attr('height', 100)
.attr('x', 0)
.attr('y', 0)

圆形

  • SVG 用 circle 标签来创建圆形
  • circle 有三个主要的属性。
    • cx 和 cy 属性是坐标。 它们告诉 D3 将图形的中心放在 SVG 画布的何处。
    • 半径( r 属性)给出 circle 的大小。
  • 和 rect 的 y 坐标一样,circle 的 cy 属性是从 SVG 画布的顶端开始测量的,而不是从底端。
js
svg
.selectAll('circle')
.data(dataset)
.enter()
.append('circle')
//散点图
.attr('cx', d => d[0])
.attr('cy', d => h - d[1])
.attr('r', '5')

比例尺

创建线性比例

条形图和散点图都直接在 SVG 画布上绘制数据。 但是,如果一组的高或者其中一个数据点比 SVG 的高或宽更大,它将跑到 SVG 区域外。

D3 中,比例尺可帮助布局数据。 scales 是函数,它告诉程序如何将一组原始数据点映射到 SVG 画布上。

线性缩放

  • 通常使用于定量数据
  • 默认情况下,比例尺使用一对一关系(identity relationship)。 输入的值和输出的值相同。
js
const scale = d3.scaleLinear()

例子

js
const scale = d3.scaleLinear() // 在这里创建轴
const output = scale(50) // 调用 scale,传入一个参数
d3.select('body').append('h2').text(output)

按比例设置域和范围

  • 域 domain:假设有一个数据集范围为 50 到 480, 这是缩放的输入信息,也被称为域。
  • 范围 range:沿着 x 轴将这些点映射到 SVG 画布上,位置介于 10 个单位到 500 个单位之间。 这是输出信息,也被称为范围。
  • domain()range() 方法设置比例尺的值, 它们都接受一个至少有两个元素的数组作为参数。
    • domain() 方法给比例尺传递关于散点图原数据值的信息
    • range() 方法给出在页面上进行可视化的实际空间信息

例子:

js
scale.domain([50, 480]); //域
scale.range([10, 500]); //范围
scale(50) //10
scale(480) //500
scale(325) //323.37
scale(750)。// 807.。67
d3.scaleLinear()

按顺序,将在控制台中显示以下值:10、500、323.37 和 807.67。

注意,比例尺使用了域和范围之间的线性关系来找出给定数字的输出值。 域中的最小值(50)映射为范围中的最小值(10)。

(也就是给定范围,用线性关系缩小,比如图片放大缩小,给了原图大小和缩小后的图片大小,根据线性关系比例来计算每个像素的位置,元素的大小)

最小值最大值

  • d3.min:最小值
  • d3.max: 最大值
  • min()max() 都可以使用回调函数,下面例子中回调函数的参数 d 是当前的内部数组。
  • min()max() 方法在设置比例尺时十分有用

例子:找到二维数组的最大值和最小值

js
const locationData = [
[1, 7],
[6, 3],
[8, 3]
]
const minX = d3.min(locationData, d => d[0]) //查找在d[0]位置上最小的值

使用动态比例

  • min()max() 来确定比例尺范围和域
  • padding 将在散点图和 SVG 画布边缘之间添加空隙。
  • 保持绘图在右上角。 当为 y 坐标设置 range 时,大的值(height 减去 padding)是第一个参数,小的值是第二个参数。
js
const dataset = [
[34, 78],
[109, 280],
[310, 120],
[79, 411],
[420, 220],
[233, 145],
[333, 96],
[222, 333],
[78, 320],
[21, 123]
]
const w = 500
const h = 500
const padding = 30
const xScale = d3
.scaleLinear()
.domain([0, d3.max(dataset, d => d[0])])
.range([padding, w - padding])

使用预定义的比例放置元素

  • 用比例尺函数为 SVG 图形设置坐标属性值。
  • 当显示实际数据值时,不用使用比例尺,例如,在提示框或标签中的 text() 方法。
js
svg
.selectAll('circle')
.data(dataset)
.enter()
.append('circle')
.attr('cx', d => xScale(d[0]))
.attr('cy', d => yScale(d[1]))
.attr('r', '5')

添加坐标轴

  • 位置:axisLeft()axisBottom()
  • g 元素, g 是英文中组(group)的缩写,在渲染时,轴只是一条直线。 因为它是一个简单的图形,所以可以用 g
  • SVG 支持多种 transforms,但是定位轴需要使用 translate 属性

例子:

js
// X轴
const xAxis = d3.axisBottom(xScale)
svg
.append('g')
.attr('transform', 'translate(0, ' + (h - padding) + ')') // translate(0,x)
.call(xAxis) // x轴作为参数被传递给 call() 方法
// Y轴
const yAxis = d3.axisLeft(yScale)
svg
.append('g')
.attr('transform', 'translate(0,' + (h - padding) + ')')
.call(xAxis)
svg
.append('g')
.attr('transform', 'translate(' + padding + ',0)')
.call(yAxis)

常见图表

散点图

圆圈来映射数据点,每个数据点有两个值。 这两个值和 x 和 y 轴相关联,在可视化中用来给圆圈定位。

js
svg
.selectAll('circle')
.data(dataset)
.enter()
.append('circle')
.attr('cx', d => d[0])
//反转图像
.attr('cy', d => h - d[1])
.attr('r', '5')
// 散点图加标签
svg
.selectAll('text')
.data(dataset)
.enter()
.append('text')
// Add your code below this line
.attr('x', d => d[0] + 5)
.attr('y', d => h - d[1])
.text(d => d[0] + ', ' + d[1])
%sveltekit.body%