数据准备:<div ref="dataRef" :class="$style.dataRef"></div>
const fData = [
{
name: '香蕉',
value: 20
},
{
name: '苹果',
value: 30
},
{
name: '李子',
value: 90
},
{
name: '猕猴桃',
value: 10
},
{
name: '橙子',
value: 60
}
];
const margin = { left: 30, top: 30, bottom: 30, right: 30 };
const width = 300;
const height = 300;
const svg = d3.create('svg').attr('viewBox', [30, 30, width, height]);
//...要进行的操作
this.$refs.dataRef.appendChild(svg.node());
1.柱状图
scaleBand
- 适用于离散型数据或分类数据,比如类别、名称等,而不是连续的数值。
- 常用于创建序数型比例尺(Ordinal Scale),它将离散的输入域映射到有限的输出范围内。
domain
包含离散的、有限的值,通常是类别的名称或者离散的标识。- 通常用于创建柱状图、分组条形图等,以及将分类数据映射到屏幕上的位置。
const x = d3
.scaleBand()
.domain(['A', 'B', 'C', 'D']) // 例如,类别或离散标识
.range([0, width])
.padding(0.1);
1-1.绘制x轴
const x = d3
.scaleBand()
.domain(d3.map(fData, d => d.name))
.range([margin.left, width - margin.left]);
const xAxis = d3.axisBottom(x).tickSizeOuter(0);
svg
.append('g')
.attr('transform', `translate(${margin.left},${height - margin.bottom})`)
.call(xAxis);
1-2.绘制y轴
scaleLinear
- 适用于连续型数据,比如数值型数据。
- 创建的是线性比例尺(Linear Scale),将输入域的连续范围映射到输出范围内。
domain
包含连续的数值范围,通常是最小值到最大值的数值范围。- 通常用于创建折线图、散点图等,以及将数值数据映射到屏幕上的位置。
const y = d3
.scaleLinear()
.domain([min, max])
.range([margin.bottom, height - margin.bottom]);
const yAxis = d3.axisLeft(y);
svg.append('g').attr('transform', `translate(${margin.left},0)`).call(yAxis);
是不是很惊奇,为什么压轴是从上往下变大的?
在可视化中,特别是在屏幕坐标系中,通常情况下,y轴的原点通常位于屏幕的左上角,而不是传统的数学坐标系中的左下角。在屏幕坐标系中,y轴向下增长,这与我们在数学课堂上使用的笛卡尔坐标系中y轴向上增长是不同的。
这种不同是因为计算机图形学的历史和屏幕显示的方式导致的。在大多数图形库中,包括D3.js,在渲染坐标轴时,默认情况下会将y轴从上到下显示,这也是为了与屏幕坐标系的方向保持一致。
虽然y轴的增长方向与我们直觉上的数学坐标系不同,但在实际的可视化中,这种方向是合理的,并且符合我们对屏幕空间的感知。如果你想要y轴向上增长,可以通过反转坐标轴的range来实现
const y = d3.scaleLinear().domain([min, max]).range([height - margin.bottom, margin.bottom]);
1-3.画条形图
在页面中添加rect和text实现条形图
修改之前代码如下:
svg
.append('g')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(xAxis)
.call(g => {
g.selectAll('.tick')
.append('rect')
.data(fData)
.join('rect')
.attr('width', 30)
.attr('height', d => height - margin.bottom - y(d.value))
.attr('fill', 'pink')
.attr('transform', d => `translate(-15,-${height - margin.bottom - y(d.value)})`);
})
.call(g =>
g
.selectAll('.tick')
.append('text')
.data(fData)
.join('text')
.attr('class', 'txt')
.attr('x', 0)
.attr('y', d => -(height - margin.bottom - y(d.value)) - 5)
.attr('text-anchor', 'middle')
.attr('fill', 'red')
.text(d => d.value)
);
2.折线图
绘制x轴和y轴原理同上,不同的就吧条形图换成折线图,下面仅是实现折现代码
2-1.绘制折现
在数据可视化中,曲线(Curves)通常指的是用来平滑连接数据点的线条或路径。在 D3.js 中,有多种类型的曲线插值器可以用来创建平滑的曲线路径,用于连接给定的数据点。
d3.line()
是 D3.js 中的一个函数,用于创建生成器(Generator)。这个生成器可以将输入的数据点数组转换为 SVG <path>
元素所需的路径字符串,以便在 SVG 中绘制线条或曲线。
通常,d3.line()
生成器会配置以下属性:
- x: 用于确定数据点的 x 坐标的函数或值。
- y: 用于确定数据点的 y 坐标的函数或值。
- curve: 确定路径的曲线插值器类型,例如线性、基数样条、单调等。
使用 D3.js 创建的 line
可以将数据点转换为 SVG 中的路径,然后将这个路径添加到 SVG 中以显示图形。要将 line
添加到 SVG 中,你需要将路径数据绑定到一个 SVG 元素上,并将路径信息设置为这个元素的 d
属性。
const line = d3
.line()
.x(d => x(d.name))
.y(d => y(d.value))
.curve(d3.curveLinear);//d3.curveLinear可根据官网更改
svg
.append('path')
.datum(fData)
.attr('d', line)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2);
2-2.给折线图添加面积
const area = d3
.area()
.x(d => x(d.name)) // 定义x坐标
.y0(height - margin.bottom) // 定义y坐标的底部值,通常是图表底部
.y1(d => y(d.value)); // 定义y坐标的顶部值,基于数据的值
svg.append('path').datum(fData).attr('d', area).attr('fill', 'steelblue').attr('opacity', 0.4);
注意:这里x轴要添加.paddingInner(1)设置分组间的内边距
Band scales | D3 by Observable
3.饼图
3-1.数据转换弧度
const pie = d3.pie()(fData.map(d => d.value));
arc弧形生成器产生圆形或环状扇形,例如馅饼或甜甜圈图表。弧线以原点为中心;变换来将弧线移动到不同的位置。
const pie = d3.pie()(fData.map(d => d.value));
// 设置每个值的弧度
const arc = d3
.arc()
.innerRadius(0)
.outerRadius(80)
.startAngle(d => d.startAngle)
.endAngle(d => d.endAngle);
svg
.selectAll('g')
.data(pie)
.join('g')
.attr('transform', 'translate(100,100)')
.call(g =>
g
.append('path')
.attr('d', arc)
.attr('fill', (d, i) => {
const color = d3.schemeCategory10;
return color[i];
})
)
.call(g =>
g
.append('text')
.attr('transform', d => `translate(${arc.centroid(d)})`)
.attr('text-anchor', 'middle')
.attr('fill', 'white')
.text(d => d.value)
);
4.雷达图
areaRadial
和 lineRadial
是 D3.js 中用于创建极坐标图表的两个不同的生成器。它们的区别在于它们的输出和用途。
-
lineRadial
生成器:- 用于创建连接数据点的径向线。
- 输出是一条连接各个数据点的线段。
- 可以用于绘制雷达图的边缘轮廓或其他径向线性图表。
-
const line = d3.lineRadial() .angle(d => /* 角度值 */) .radius(d => /* 半径值 */);
-
areaRadial
生成器:- 用于创建填充了数据区域的径向区域图。
- 输出是一个封闭的区域,通过指定的曲线描绘出数据的形状。
- 通常用于绘制雷达图的填充区域,显示数据在各个维度上的分布情况。
-
const area = d3.areaRadial() .angle(d => /* 角度值 */) .radius(d => /* 半径值 */);
在上述代码中,angle
和 radius
方法用于指定在极坐标中数据点的角度和半径的映射。这两个生成器都可以与适当的比例尺(如 scaleBand
、scaleLinear
、scaleRadial
)一起使用,以确保数据正确地映射到图表中。
总体来说,lineRadial
主要用于绘制连接数据点的线,而 areaRadial
用于绘制填
Radial area chart / D3 | Observable 参考官方这个案例更改
4-1.绘制比例尺
const width = 400;
const height = 400;
const innerRadius = 0;
const outerRadius = width / 2;
const svg = d3.create('svg').attr('viewBox', [-width / 2, -height / 2, width, height]);
const x = d3
.scaleBand()
.domain(d3.map(fData, d => d.name))
.range([0, 2 * Math.PI]);
const y = d3.scaleRadial().domain([0, 100]).range([innerRadius, outerRadius]);
this.$refs.dataRef.appendChild(svg.node());
4-2.绘制形状
const area = d3
.areaRadial()
.curve(d3.curveLinearClosed)
.angle(d => x(d.name))
.innerRadius(y(min))
.outerRadius(y(max));
svg
.append('path')
.attr('fill', 'lightsteelblue')
.attr('fill-opacity', 0.2)
.attr('d', area(fData))
.attr('stroke', 'currentColor');
svg
.append('g')
.selectAll('g')
.data(fData)
.join('g')
.call(g =>
g
.append('path')
.attr('stroke', '#000')
.attr('stroke-opacity', 0.2)
.attr(
'd',
d => `
M${d3.pointRadial(x(d.name), innerRadius)}
L${d3.pointRadial(x(d.name), outerRadius)}
`
)
);
4-3.根据数据绘制区域
const line = d3
.lineRadial()
.curve(d3.curveLinearClosed)
.angle(d => x(d.name));
svg
.append('path')
.attr('fill', 'pink')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('d', line.radius(d => y(d.value))(fData));