工欲善其事,必先利其器。在了解D3对SVG的核心操作之前,我们首先需要知道什么是SVG,以及SVG绘图的基本用法。
SVG可缩放矢量图形是一种基于可扩展标记语言,用于描述二维矢量图形的图形格式。SVG由W3C制定,是一个开放标准。
通过SVG绘制图形
SVG根视图
SVG根视图可以认为就是一块画布,所有绘图工作都是在SVG那实现的。SVG初始化时需要配置一些参数:
version
:SVG的版本xmlns
: 命名空间width
和height
:SVG画布的吃顿viewBox
:视图框,总会在画布中完全显示,其中的图形会基于视图框的宽高按比例显示
<svg version="1.2"
xmlns="http://www.w3.org/2000/svg"
width="400"
height="400"
viewBox="0 0 400 400"
></svg>
声明好SVG跟容器之后,我们就可以在svg标签内部进行绘图了,常见的图形如下:
- 矩形
- 圆形
- 路径 ==> 万能绘图方式
- 直线
- 圆弧
- 二次贝塞尔曲线
- 二次贝塞尔曲线的延续
- 三次贝塞尔曲线
下面我们来一个一个的看如何绘制上述图形。
矩形
<!--
rect 矩形
x|y 矩形左上角点位置
width|height 尺寸
-->
<rect x="100" y="100" width="400" height="400" fill="#00acec" />
圆形
<!--
circle 圆形
cx|cy 圆心位置
r 半径
-->
<circle cx="300" cy="300" r="100" fill="#00acec" />
路径 - 直线
关于路径(也就是线条),有几个常用的属性,用来控制路径的样式:
fill
用来控制路径内部的填充色(闭合曲线才生效)stroks
用来控制路径线条的颜色stroke-width
用来控制线条的宽度stroke-dasharray
用来控制线条的连续性,常用来绘制虚线
<!--path 路径
d 路径形状,大写字母为绝对点位,小写字母为相对点位
起点: M|m
下一个点: L|l
-->
<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 是否显示最大弧 0|1
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"
/>
路径 - 二次贝塞尔曲线
<!--二次贝塞尔曲线 Q|q,如
M 100 400
Q 200 100 300 400
其中200 100 分别是 cpx1 cpy1 控制点,用来控制曲线的弯曲程度
其中300 400 分别是 x y 结束点
-->
<path
d="
M
100 400
Q
200 100
300 400
"
fill="none"
stroke="#000"
stroke-width="10"
/>
二次贝塞尔曲线的延续
上述我们通过Q|q生成了一段二次贝塞尔曲线,如果我们想要接着画,就需要通过T|t声明接下来曲线的所有控制点。
<!--二次贝塞尔曲线的延续 T|t,如T 500 400
x y 结束点
x y 结束点
……
-->
<path
d="
M
100 400
Q
200 100
300 400
T
500 400
700 400
900 400
"
fill="none"
stroke="#000"
stroke-width="10"
/>
三次贝塞尔曲线
三次贝塞尔曲线与上述二次曲线除了声明的参数变成了C|c以外,唯一的不同之处就在于控制点从一个变成了两个
<!--三次贝塞尔曲线 C|c,如 M 100 400 C 200 400 200 200 300 200
上述的 C 200 400 是 cpx1 cpy1 控制点1
紧接在 C 200 400 后面的 200 200 是cpx2 cpy2 控制点2
最后的 300 200 是 x y 结束点
-->
<path
d="
M
100 400
C
200 400
200 200
300 200
"
fill="none"
stroke="#000"
stroke-width="10"
/>
三次贝塞尔曲线的延续
同上,只需要在继续通过S|s声明所有控制点即可,这时通过S|s声明的控制点只需要声明控制点2即可:
<!--三次贝塞尔曲线的延续 S|s,如 S 400 400 500 400
上述的S 400 400 是 cpx2 cpy2 控制点2
500 400 是 x y 结束点
-->
<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="10"
/>
图形容器
上述的路径属性都用到了一些相同的属性,如fill
stroke
等,每个path标签内都写这些重复的属性,显然是不够优雅的。并且,如果项目很大,这么多类似的path标签,写着写着我们就不知道哪个path标签对应什么功能了,不便于我们管理。
所以D3提供了图形容器g,用来统一管理处理同一对象或者同一任务的图形,并管理公共属性。
<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>
设置SVG的样式
其实在上面绘制图形的时候已经通过fill
stroke
等属性控制SVG样式了,现在我们以控制SVG图形的颜色为例,来看看详细一下如何设置SVG样式。
着色按照着色区域可以分为“填充区域”和“描边区域”
fill
属性,用来控制填充区域颜色,默认为black,负责填充图形内部的颜色stroke
属性,用来控制描边区域,默认为none,负责描边,填充图形轮廓的颜色
<circle cx="300" cy="300" r="200" fill="rgba(255,100,0,0.5)"/>
<circle cx="300"
cy="300"
r="200"
fill="none"
stroke="#00acec"/>
上面都是只填充了纯色,事实上可以使用多种不同着色方式:
- 纯色
- 渐变色
- 线性渐变
- 径向渐变
- 纹理
渐变 - 线性渐变
通过linearGradient
标签声明线性渐变参数,相关API可详见MDN。
在标签内通过gradientTransform
属性声明渐变转换的参数:
rotate(a)
控制线性旋转的角度translate(x,y)
控制x、y方向上的移动scale(sx,sy)
控制x、y方向上的缩放
在 linearGradient
内通过 stop
子标签声明填充的节点颜色。
offset
偏移量[0,1]stop-color
颜色
最后在图形标签内,通过 fill="url(#id)"
调用渐变填充颜色
<defs>
<linearGradient
id="gr"
gradientTransform="rotate(30)"
>
<stop offset="0" stop-color="#fff" />
<stop offset="0.5" stop-color="#00acec" />
<stop offset="1" stop-color="#fff" />
</linearGradient>
</defs>
<circle cx="300" cy="300" r="200" fill="url(#gr)"/>
渐变 - 径向填充
通过 radialGradient
标签声明径向填充,其余完全一致。
<defs>
<linearGradient
id="gr"
gradientTransform="rotate(30)"
>
<stop offset="0" stop-color="#fff" />
<stop offset="0.5" stop-color="#00acec" />
<stop offset="1" stop-color="#fff" />
</linearGradient>
</defs>
<circle cx="300" cy="300" r="200" fill="url(#gr)" />
纹理着色
可以通过绘制好的SVG图形或者插入的图片,来对图形内部进行纹理填充。
-
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">
<!--<polygon points="0,0 20,50 0,100 50,80 100,100 80,50 100,0 50,20"/>-->
<image href="./images/rose.jpg" width="100" height="100" />
</pattern>
</defs>
<circle cx="300" cy="300" r="200" fill="url(#pt)" />
利用D3绘图
上面已经基本搞通了SVG是如何绘制图形以及如何设置样式的了,那么就通过D3操作DOM元素和SVG,来绘制一个图形吧。
step1 通过D3的 select
方法获取到main容器。
const main=d3.select('#main')
step2 在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')
step3 在svg容器中建立svg图形,并设置相关属性
svg.append('rect')
.attr('x',-200)
.attr('y',-100)
.attr('width',400)
.attr('height',200)
.attr('fill','red')
然后以此类推在svg容器里面添加各种各样的图形,可是我们会发现,这样写要写很多的appen方法,很多很多的attr方法,很不优雅。回过头一看,发现:不管是在main里建立svg容器,还是在svg容器里面添加图形,整体的调用逻辑都是一样的。因此我们可以把这一系列的调用逻辑封装成一个方法。
step4 封装Render
方法,该方法以真实DOM节点作为参数传入,然后返回一个真正的处理函数。该返回函数以需要生成的元素节点和节点属性项为参数传入,并返回真实的元素节点。
function Render(dom) { // 真实的DOM节点作为参数传入,并直接返回一个处理函数
return function(shape,option){ // 想要生成的DOM节点、节点配置作为参数传入
const obj=dom.append(shape)
for(let [key,val] of Object.entries(option)){
// 遍历所配置项,并赋值给DOM节点对象
obj.attr(key,val)
}
return obj
}
}
这样,我们就可以直接优雅的通过Render
方法添加DOM节点了:
/*获取main 容器*/
const main = d3.select("#main");
function Render(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 = Render(main)("svg", {
version: 1.2,
xmlns: "http://www.w3.org/2000/svg",
width: "100%",
height: "100%",
viewBox: "-400 -400 800 800",
});
// 获取到创建DOM节点的方法
const draw = Render(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,
});
以上,便是通过D3操作DOM实现SVG绘图的实例。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!