d3基础知识
元素选择
- 通过 css 选择器选择
- 通过 dom 对象选择
- 通过原生 js 获取 title 元素
- 多选
- 过滤元素
<h1 id="title">
<p></p>
<p></p>
<p></p>
<p></p>
</h1>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
d3.select("#title").classed('sky', true);
d3.select("p").classed('sky', true);
const title = document.querySelector("#title");
d3.select(title).classed('sky', true);
d3.selectAll('p').classed('sky', true);
d3.selectAll('p:nth-child(2)').classed('sky', true);
d3.selectAll('p:nth-child(even)').classed('sky', true);
d3.selectAll('p').filter((ele, ind) => (ind%2) == 1).classed('sky', true);;
const n = [1, 2, 3];
d3.selectAll('p').filter((ele, ind) => n.includes(ind)).classed('sky' ,true);
</script>
设置元素样式
-
设置 dom 内联样式
style 内联样式
classed 增删 class
attr 设置属性,会覆盖先前的属性值
-
style() 方法设置标题颜色
-
attr() 方法通过 style 属性的设置,改变标题颜色
-
classed(class, true | false) 方法增删标题的 class
-
attr() 方法设置 class 属性
-
用 style 的回调函数,让所有 p 元素偶数行变蓝
-
用 data 数据绑定,动态设置 p 元素的字体大小
const title = d3.select('#title');
title.style('color', 'red');
title.attr('style', 'color: red');
title.classed('sky', true);
// 前者不会覆盖,后者会覆盖掉前面的 class 属性值
title.attr('class', true);
d3.selectAll('p').style('color', (ele, ind) => ind%2 ? 'red' : 'black');
const data = [12, 16, 17, 24, 56];
d3.selectAll('p').data(data).style('font-size', (ele, ind) => {
return `${ele}px`
});
d3.selectAll('p').data(data).style('font-size', (ele, ind) => `40px`);
设置元素属性
-
设置 dom 属性
attr 设置普通的内置属性和自定义属性
property 设置特殊的内置属性
-
基于答案,选择相应的选项
d3.selectAll('label').attr('class', 'opt');
const answer = [0, 1];
d3.selectAll('input')
.filter((ele, ind) => answer.includes(ind))
.property('checked' ,true);
设置元素内容
- text 文本内容
- html html 内容
const title = d3.select('#title');
const titleText = "123";
const p = `
<p></p>
`;
title.text(titleText);
title.html(p);
增删元素
- 添加 DOM 元素
- append 在当前选择集的最后追加指定名称的子元素
- insert 前置元素,可声明在哪个元素前添加
- data + join 以完全覆盖的方式添加元素
- data + enter + append 以差值的方式添加元素
<body>
<h1 id="title">沁园春·长沙</h1>
<article id="cont"></article>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
const arr=[
'作者:毛主席',
'独立寒秋,湘江北去,橘子洲头。',
'看万山红遍,层林尽染;漫江碧透,百舸争流。',
'鹰击长空,鱼翔浅底,万类霜天竞自由。',
'怅寥廓,问苍茫大地,谁主沉浮?',
'携来百侣曾游。忆往昔峥嵘岁月稠。',
'恰同学少年,风华正茂;书生意气,挥斥方遒。',
'指点江山,激扬文字,粪土当年万户侯。',
'曾记否,到中流击水,浪遏飞舟?'
]
const cont=d3.select('#cont');
cont.append('p')
.text('独立寒秋,湘江北去,橘子洲头。---------')
.attr('id', 'p1');
cont.insert('p', '#p1')
.text('123');
cont.selectAll('p')
.data(arr)
.join('p')
.text(d=>d)
const.selectAll('p')
.data(arr)
.enter()
.append('p')
.text(d=>d)
</script>
</body>
- 删除 DOM 元素
d3.select('p').remove();
// 删除第一个元素
svg
svg 绘图方式
- svg 根节点
- version svg 版本号
- xmlns 命名空间 http://www/w3.org/2000/svg
- width | height svg 画布尺寸,如 400 ,400
- viewBox 视图框,总会在画布中完全显示,其中的图形会基于视图框的宽高按比例显示
<svg version="1.2"
xmlns="http://www.w3.org/2000/svg"
width="400"
height="400"
viewBox="0 0 400 400"
>
<!-- viewBox 中的远点位置是根据自身宽高和总外 svg 层宽高等比在视图的位置,而内置元素的宽高就得在这个比例基础上换算 -->
<rect width="400" height="400" fill="red" />
</svg>
- svg 图形绘制
- rect
- circle
- path
- 直线
- 圆弧
- 二次贝塞尔曲线
- 三次贝塞尔曲线
- 圆形容器
<!--
rect: x | y 矩形左上角点位置
width | height 尺寸
-->
<rect x="100"
y="100"
width="400"
height="400"
fill="red"
/>
<!--
circle: cx | cy 圆心位置
r 半径
-->
<circle cx="300"
cy="300"
r="100"
fill="red"
/>
<!--
path路径: d 路径形状,大写字母为绝对点定位,小写字母为相对点定位
起点: M | m
下一个点: L | l
圆弧: A | a
二次贝塞尔曲线: Q | q, T | t
三次贝塞尔曲线: C | c, S | s
闭合路径 Z | z
-->
<path d="
M
300 300
L
500 300
"
fill="none"
stroke="#000"
stroke-width="10"
stroke-dasharray="30 10"
/>
<!--
圆弧: A | a ,如 M 300 300 A 150 200 0 0 0 500 300
rx, ry 半径
x-axis-rotation x 轴方向[0, 360]
large-arc-flag 是否显示最大弧
sweep-flag 弧在哪一侧 0 | 1
x y 结束点
-->
<path d="
M 300 300
A 150 200 20 1 0 500 300
"
fill="none"
stroke="#000"
stroke-width="5"
/>
<!-- 放在一个容器内,把共有属性抽离在容器标签内 -->
<g fill="none" stroke="#000">
<path d="
M
100 400
L
200 400
200 200
300 200
400 400
500 400
"
stroke-width="2"
stroke-dasharray="3"
/>
<path d="
M
100 400
C
200 400
200 200
300 200
S
400 400
500 400
600 200
700 200
"
stroke-width="10"
/>
</g>
二次贝塞尔曲线
<!--
二次贝塞尔曲线: Q | q, 如 M 100 400 Q 200 100 300 400
cpx1 cpy1 控制点
x y 结束点
二次贝塞尔曲线延续: T | t, 如 T 500 400
-->
<path d="
M
100 400
L
200 100
300 400
"
fill="none"
stroke="#000"
stroke-width="2"
stroke-dasharray="3"
/>
<path d="
M
100 400
Q
200 100
300 400
T
500 400
700 400
"
fill="none"
stroke="#000"
stroke-width="5"
/>
<circle cx="100" cy="400" r="10" fill="red" />
<circle cx="200" cy="100" r="10" fill="red" />
<circle cx="300" cy="400" r="10" fill="red" />
<circle cx="500" cy="400" r="10" fill="red" />
<circle cx="700" cy="400" r="10" fill="red" />
延续的周期只需要描绘一个点,(上一个点x值 + 周期 T,上一个点y值)
三次贝塞尔曲线
<!--
三次贝塞尔曲线:C | c, 如 M 100 400 C 200 400 200 200 300 200
cpx1 cpy1 控制点1
cpx2 cpy2 控制点2
x y 结束点
三次贝塞尔曲线的延续: S | s, 如 s 400 400 500 400
-->
<path d="
M
100 400
L
200 400
200 200
300 200
400 400
500 400
600 200
700 200
"
fill="none"
stroke="#000"
stroke-width="2"
stroke-dasharray="3"
/>
<path d="
M
100 400
C
200 400
200 200
300 200
S
400 400
500 400
600 200
700 200
"
fill="none"
stroke="#000"
stroke-width="5"
/>
<circle cx="100" cy="400" r="10" fill="red" />
<circle cx="200" cy="400" r="10" fill="red" />
<circle cx="200" cy="200" r="10" fill="red" />
<circle cx="300" cy="200" r="10" fill="red" />
<circle cx="400" cy="400" r="10" fill="blue" />
<circle cx="500" cy="400" r="10" fill="blue" />
<circle cx="600" cy="200" r="10" fill="blue" />
<circle cx="700" cy="200" r="10" fill="blue" />
周期的规律:接下来的四个点画出下一个半周期图形
svg样式
- 着色区域
- fill 填充区域,默认 blank
- stroke 描边区域,默认 none
<circle cx="300"
cy="300"
r="200"
fill="red"
/>
-
着色方式
- 纯色
<circle cx="300" cy="300" r="200" fill="red" />-
渐变色
- 线性渐变
<!--linearGradient 线性渐变 gradientTransform 渐变变换 https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function rotate(a) 旋转[0,360] translate(x,y) 移动 scale(sx,sy) 缩放 stop 颜色节点 offset 偏移量[0,1] stop-color 颜色 渐变色的赋值 url(id) --> <defs> <linearGradient id="gr" gradientTransform="rotate(30)" > <stop offset="0" stop-color="#fff"/> <stop offset="0.5" stop-color="#00acae"/> <stop offset="1" stop-color="#fff" /> </linearGradient> </defs> <circle cx="300" cy="300" r="200" fill="url(#gr)" />- 径向渐变
<!--radialGradient 径向渐变 stop 颜色节点 offset 偏移量[0,1] stop-color 颜色 --> <defs> <radialGrandient id="gr"> <stop offset="0" stop-color="#fff"/> <stop offset="0.5" stop-color="#00acec"/> <stop offset="1" stop-color="#fff"/> </radialGrandient> </defs> <circle cx="300" cy="300" r="200" fill="url(#gr)" /> -
纹理
- 注意插入图片边距(无边距图后宽高也必须和 viewBox 宽高一致)
<!--pattern 纹理着色 id viewBox 视图框 width height 纹理元素的尺寸,建议使用百分百 polygon 多边形 points 点位,如 0,0 20,50 0,100 50,80 100,100 80,50 100,0 50,20 image href 图片地址 x|y 位置 widht|height 宽高 --> <polygon points="0,0 20,50 0,100 50,80 100,100 80,50 100,0 50,20"/> <defs> <pattern width="30%" height="30%" viewBox="0 0 100 100" id="pt" > <image href="./images/rose/jpg" width="100" height="100" /> </pattern> </defs> <circle cx="300" cy="300" r="200" fill="url(#pt)" />
svg封装
<body>
<div id="main"></div>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
const main = d3.select('#main');
function Draw(dom) {
return function(shape, option) {
const obj = dom.append(shape);
for(let [key, val] of Object.entries(option)) {
obj.attr(key, val);
}
return obj;
}
}
const svg = Draw(main)('svg', {
version: 1.2,
xmlns: 'https://www.w3.org/2000/svg',
width: '100%',
height: '100%',
viewBox: '-400 -400 800 800'
})
// 建立以 svg 为容器的绘图方法
const draw = Draw(svg);
draw('rect', {
x:-200
})
</script>
</body>
const rectCom={
x:-200,
y:0,
width:400,
height:200,
}
draw('rect',{
...rectCom,
fill:red
});
使用上述封装方法绘制一个机器人
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>机器人-d3</title>
<style>
html{height: 100%}
body{height: 100%;margin: 0;}
#main{
width: 100%;
height: 100%;
background-color: antiquewhite;
}
</style>
</head>
<body>
<div id="main"></div>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
/*获取main 容器*/
const main=d3.select('#main')
/*在main容器中建立svg,并设置其相关属性*/
/*const svg=main.append('svg')
.attr('version',1.2)
.attr('xmlns','http://www.w3.org/2000/svg')
.attr('width','100%')
.attr('height','100%')
.attr('viewBox','-400 -400 800 800')*/
const svg=Draw(main)('svg',{
version:1.2,
xmlns:'http://www.w3.org/2000/svg',
width:'100%',
height:'100%',
viewBox:'-400 -400 800 800'
})
/*建立绘图函数Draw,以dom容器为参,返回绘图方法
* 绘图方法以图形shape和配置项option为参
* 用append方法向容器中添加图形obj
* 用for……of……的方法,遍历Object.entries(配置项)的键值对
* 用attr方法设置图形obj的属性
* 返回图形obj
* */
function Draw(dom) {
return function(shape,option){
const obj=dom.append(shape)
for(let [key,val] of Object.entries(option)){
obj.attr(key,val)
}
return obj
}
}
/*建立以svg为容器的绘图方法draw*/
const draw=Draw(svg)
/*绘制图形……*/
draw('rect',{
x:-200,
y:0,
width: 400,
height: 200,
fill:'red'
})
draw('rect',{
x:-200,
y:0,
width: 400,
height: 200,
fill:'none',
stroke:'#000',
'stroke-width':40,
})
draw('rect',{
x:-200,
y:50,
width: 400,
height: 60,
fill:'antiquewhite'
})
draw('path',{
d:`
M
-100 150
L
100 150
`,
fill:'none',
stroke:'#000',
'stroke-width':40,
})
draw('circle',{
cx:-100,
cy:80,
r: 20,
fill:'red'
})
draw('path',{
d:`
M
80 90
A
20 20
0
0
1
120 90
`,
fill:'red'
})
draw('path',{
d:`
M
-200 -200
C
-100 -200
-100 0
0 0
S
100 -200
200 -200
`,
fill:'none',
stroke:'#000',
'stroke-width':40,
})
</script>
</body>
</html>