1. d3是什么
D3 的全称是(Data-Driven Documents),顾名思义可以知道是一个被数据驱动的文档。就是一个 JavaScript 的函数库,使用它主要是用来做数据可视化的。D3 已经将生成可视化的复杂步骤精简到了几个简单的函数,你只需要输入几个简单的数据,就能够转换为各种图形。
为什么使用D3.js
我们知道现在有很多开源的图表库Echarts、G2.js等等。那么D3跟这些图表库相比有什么优势和劣势?
-
D3 基于svg,因此对图像进行放大不会失真。
-
D3 相对来说较底层,对初学者来说不太方便,但是一旦掌握了,就比其他工具更加得心应手。下图展示了
-
D3 与其它可视化工具的区别:
2. d3-selection
选择图元
d3.select('.class2')
d3.selectAll('.class2')
d3.selectAll('#maingroup .class2')
复制代码
修改图元
selection.attr(name[, value]) (替换)
selection.style(name[, value[, priority]])
selection.classed(name[, value]) (增加/删除某个calss)
// value存在:正常值,设置属性,返回null,或者false就是删除属性
// value 不存在就是返回true/false
复制代码
增加图元
//如果指定的 type 为字符串则创建一个以此字符串为标签名的元素,并将其追加到选择集元素列表中
selection.append(type)
// 如果指定了 value 则将选中的元素的 text content 设置为指定的值
selection.text().
// 如果指定了 value 则将选中的元素的 inner HTML 设置为指定的值,会替代任何现有的子元素
selection.html().
复制代码
删除图元
selection.remove()
复制代码
绑定数据
selection.data().
// 将指定数组的数据 data 与已经选中的元素进行绑定并返回一个新的选择集,
// 返回的新的选择集使用 update 表示: 此时数据已经成功的与元素绑定。
selection.enter () // 数据比图元多,增加图元
selection.exit() // 图元比数据多,删除图元
selection.join() // 自动增加/删除图元
复制代码
事件绑定
selection.on(typenames[, listener[, capture]])
// 为每个选中的元素添加或者移除(listener为null)一个指定typenames 事件的 listener
复制代码
以上建议动手试一试,自己熟悉一下API,可以用下面我的代码试试,
具体详细的API参考:www.d3js.org.cn/document/d3…
<!DOCTYPE html>
<html>
<head>
<title>Data Visualization</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg width="1600" height="800" id="mainsvg" class="svgs">
<g id='maingroup' transform='translate(100, 100)'>
<circle id='circle1'
stroke='black' r='66' fill='#4B8E6F' cx='0'></circle>
<rect id='rect1' class='class2'
stroke='black' height='200' width='66' fill='#ff8603' x='100' y='-100'></rect>
<rect id='rect2' class='class1'
stroke='black' height='200' width='66' fill='#ffde1d' x='200' y='-100'></rect>
<rect id='rect3' class='class1'
stroke='black' height='200' width='66' fill='#7289AB' x='300' y='-100'></rect>
<text id='myText' class='class2'
stroke='yellow' font-size='2em' x='400' fill='#1e9d95'>Hey D3! </text>
</g>
<g id='secondgroup' transform='translate(550, 100)'>
<rect id='rect4' class='class2'
stroke='black' height='200' width='66' fill='#DD6B66' x='100' y='-100'></rect>
<rect id='rect5' class='class1'
stroke='black' height='200' width='66' fill='#759AA0' x='200' y='-100'></rect>
<rect id='rect6' class='class1'
stroke='black' height='200' width='66' fill='#E69D87' x='300' y='-100'></rect>
</g>
</svg>
<script>
// write your practice here...
</script>
</body>
</html>
复制代码
3. 绘制条形图
数据准备
let data = [
{ type: '汽车', value: 34 },
{ type: '建材家居', value: 85 },
{ type: '住宿旅游', value: 103 },
{ type: '交通运输与仓储邮政', value: 142 },
{ type: '建筑房地产', value: 251 },
{ type: '教育', value: 367 },
{ type: 'IT 通讯电子', value: 491 },
{ type: '社会公共管理', value: 672 },
{ type: '医疗卫生', value: 868 },
{ type: '金融保险', value: 1234 }];
复制代码
创建画布
在画图之前需要创建一个画布用来布局
<svg width="1040" height="500" id="mainsvg" class="svgs"></svg>
// 数据处理,因为我们想要显示百分比,而原始数据中没有所以需要这一步
const sum = d3.sum(data, d => d.value);
data = data.map(d => {
d.precent = d.value / sum;
return d;
})
复制代码
d3-scale 比例尺
- 将抽象的维度数据映射为可视化表示。用于把实际的数据空间映射到屏幕的空间
- 比例尺很重要会经常传给坐标着和数据
d3.scaleLinear()
d3.scaleBand() // 分段比例尺
d3.scaleOrdinal(). // 序数比例尺的输出域和输入域都是离散的。例如序数比例尺可以将一组命名类别映射到一组颜色
band.bandwidth() 每个分段的宽度
continuous.domain([domain]). // 真实的数据
continuous.range([range]) // 映射到出来的数据
复制代码
创建比例尺
const xScale = d3.scaleLinear().domain([0, d3.max(data, d => +d.precent)])
.range([0, innerWidth]).nice();
// .nice()是为了显示完整的段,这个方法通常会修改 domain 将其扩展为最接近的整数值
const yScale = d3.scaleBand().domain(data.map(d => d.type)).range([innerHeight, 0]);
复制代码
d3-axis 坐标轴
d3.axisBottom(scale) // 构建一个刻度在下的坐标轴生成器
d3.axisLeft(scale) // 构建一个刻度在左的坐标轴生成器
复制代码
创建坐标轴
const xAxis = d3.axisBottom(xScale).tickSize(innerHeight).ticks(5, '.1%');
const yAxis = d3.axisLeft(yScale);
const g = svg.append('g').attr('id','maingroup')
.attr('transform', `translate(${margin.left},${margin.top})`);
g.append('g').attr('class', 'xAxis').call(xAxis);
g.append('g').attr('class', 'yAxis').call(yAxis);
复制代码
绘图
const barGroup = g.append('g').attr('id', 'barGroup').selectAll('rect').data(data).join('rect')
.attr('fill', '#007aff')
.attr('height', yScale.bandwidth() - 10) // 计算矩形高度
.attr('y', d => yScale(d.type) + 5) // 矩形的 y 位置
.transition().duration(1000) // 动画
.attr('width', d => xScale(+d.precent)) // 执行的动画,将 width 从0 变成 计算出来的值
.end();
复制代码
// 画 文本
const barText = g.append('g').attr('id', 'barText');
barText.selectAll('text').data(data).join('text')
.attr('x', d => xScale(+d.precent))
.attr('y', d => yScale(d.type))
.attr('dx', '1em')
.attr('dy', '1.6em')
.attr('font-size', '12')
.attr('color', '#475669')
.attr('line-height', 1.5)
.text(d => `${d.value} 人 ${d3.format(".2%")(d.precent)}`);
复制代码
let toolTip;
let toolTipGroup;
// 画 hover 矩形
const barHover = g.append('g').attr('id', 'barHover');
barHover.selectAll('rect').data(data).join('rect')
.attr('fill', '#ccd6ec')
.attr('y', d => yScale(d.type))
.attr('width', innerWidth + margin.right)
.attr('height', yScale.bandwidth())
.attr('opacity', '0')
.on('mousemove',function(){
this.setAttribute('opacity','0.3');
// 画tooltip
toolTip.attr('x', event.x - margin.left).attr('y', event.y - margin.top ).attr('opacity','0.8');
})
.on('mouseout', function(){
this.setAttribute('opacity','0');
toolTip.attr('opacity','0');
})
复制代码
// 画 toolTip 效果
toolTipGroup = g.append('g').attr('id', 'toolTipGroup')
toolTip = toolTipGroup.append('rect')
.attr('class', 'toolTip')
.attr('width','60')
.attr('height','60')
.attr('fill','black')
.attr('opacity','0');
复制代码
// 修改 y 轴 label 的样式
d3.selectAll('.tick text')
.attr('fill','rgb(146, 146, 146')
.attr('font-size','12')
.attr('dy','0.32em')
d3.selectAll('.yAxis line').remove();
d3.selectAll('.yAxis path').remove();
d3.selectAll('.xAxis path').remove();
d3.selectAll('.xAxis text').attr('transform', `translate(0, ${-innerHeight - 20})`);
d3.selectAll('.xAxis line').attr('stroke', '#dddddd').attr('stroke-opacity', '0.8');
复制代码
让条形图动起来
const barGroup = g.append('g').attr('id', 'barGroup').selectAll('rect').data(data).join('rect')
.attr('fill', '#007aff')
.attr('height', yScale.bandwidth() - 10)
.attr('y', d => yScale(d.type) + 5)
.transition().duration(1000)
.attr('width', d => xScale(+d.precent))
.end();
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END