D3 路径模块
D3 提供了基本图元模块 d3-path 用于将画布 Canvas 绘制路径的方法序列化 serialize,转换为适用于 SVG 作为路径元素 path 的属性 d 的字符串。
基于该模块所编写的(路径绘制)代码,可以轻松地实现在画布和 svg 两种不同的环境的适配,就可以做到一份代码在两种不同的渲染环境画出相同的路径形状
// 传入的参数 context 是路径序列化器
// 该方法是设置路径序列化器,让它在画布中绘制一个圆
function drawCircle(context, radius) {
context.moveTo(radius, 0);
context.arc(0, 0, radius, 0, 2 * Math.PI);
}
const context = d3.path();
// 配置路径序列化器
// 生成在画布 canvas 上绘制路径的指令/命令/方法
drawCircle(context, 40);
// 通过调用路径序列化器的方法 context.toString() 将在画布中绘制路径的方法转换为字符串
// 可以应用到 svg 的 <path> 元素的属性 d 上
pathElement.setAttribute("d", context.toString());
该模块所提供的 API
d3.path()
创建一个(画布)路径绘制方法的序列化器(以下简称为path
路径序列化器)
提示
D3 提供了另一种方法 d3.pathRound(number)
用于创建序列化器
该方法和 d3.path()
类似,也具有相同的方法,可以调用它们在画布中绘制路径;也具有 path.toString()
方法将绘制方法序列化为字符串
所不同的是 d3.pathRound(number)
可以接受一个参数,其值是数字,用于约束/限制转换/序列化为字符串时的坐标精度,通过设置数值的精度可以调整所生成的字符串的大小
参数 number
的默认值为 3
, 即转换为字符串时其中关于坐标的数值,其小数点后最大保留位数为千分位
序列化器是一个对象,提供了一系列的方法,可以调用它们在画布中绘制路径(它们与画布上下文 context 所提供的绘制路径的原生方法一一对应)
在画布中绘制路径的原生方法
在画布 canvas 中可以调用一系列相关的方法,通过 创建路径 Path 来创作出一个复杂的形状
以下是一些常用于在画布上绘制路径的方法:
- 使用 canvas 对象(内容)方法
beginPath()
「声明」需要创建一个新的路径 - 配合使用canvas 对象(内容)方法
moveTo(x, y)
和lineTo(x, y)
创建路径,前一个方法确定路径开始点,后一个方法基于上方的坐标和该方法给出的坐标之间创建一条路径 - 使用 canvas 对象(内容)方法
fill()
或stroke()
结束路径并创建实心或空心的图形
// 绘制一个正方形(仅有描边,不带填充)
ctx.strokeRect(50, 50, 100, 100);
// 绘制路径
ctx.beginPath();
ctx.moveTo(75, 75);
ctx.lineTo(125, 75);
ctx.lineTo(125, 125);
ctx.lineTo(75, 75);
ctx.fill();
path.moveTo(x, y)
移动画笔到画布中指定的点(x, y)
相当于画布上下文 context 的原生方法context.moveTo
如果进行序列化,则对应于 SVG 的路径字符串的移动命令M
或m
path.lineTo(x, y)
从当前位置绘制一条线到指定的点(x, y)
相当于画布上下文 context 的原生方法context.lineTo
如果进行序列化,则对应于 SVG 的路径字符串的移动命令L
或l
,H
或h
,以及V
或v
path.rect(x, y, w, h)
以四个点(x, y)
、(x+w, y)
、(x+w, y+h)
、(x, y+h)
为顶点绘制一个四边形
相当于画布上下文 context 的原生方法context.rect
如果进行序列化,则对应于 SVG 的路径字符串的移动命令L
或l
,H
或h
,以及V
或v
path.quadraticCurveTo(cpx, cpy, x, y)
从当前位置绘制一条二次贝塞尔曲线 Quadratic Bézier curve 到指定点(x, y)
,其中控制点为(cpx, cpy)
相当于画布上下文 context 的原生方法context.quadraticCurveTo
如果进行序列化,则对应于 SVG 的路径字符串的移动命令Q
或q
,以及T
或t
path.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x, y)
从当前位置绘制一条三次贝塞尔曲线 Cubic Bézier curve 到指定点(x, y)
,其中两个控制点为(cpx1, cpy1)
和(cpx2, cpy2)
相当于画布上下文 context 的原生方法context.bezierCurveTo
如果进行序列化,则对应于 SVG 的路径字符串的移动命令C
或c
,以及S
或s
path.arc(x, y, radius, startAngle, endAngle[, anticlockwise])
绘制一条弧线
以(x, y)
作为中心点,以radius
为半径,以startAngle
为起始角,以endAngle
为终止角绘制一段圆弧。如果anticlockwise
为true
,则以逆时针方向绘制圆弧;否则以顺时针方向绘制。
如果当前点不等于圆弧起点,则从当前点绘制一条直线到圆弧起点。
相当于画布上下文 context 的原生方法context.arc
如果进行序列化,则对应于 SVG 的路径字符串的移动命令A
或a
path.arcTo(x1, y1, x2, y2, radius)
从当前的点开始绘制一条弧形- 参数
radius
是弧形的半径 - 参数指定的点
(x1, y1)
与当前点(开始点)所连成的直线,与圆弧相切 - 参数指定的点
(x1, y1)
与(x2, y2)
(结束点)所连成的直线,与圆弧相切
如果第一个切点与当前点(开始点)不一致,则会在当前点和第一个切线点之间绘制一条直线。
相当于画布上下文 context 的原生方法context.arcTo
如果进行序列化,则对应于 SVG 的路径字符串的移动命令A
或a
- 参数
path.closePath()
结束当前的路径,并自动从当前的点到路径的初始点绘制一条直线,使得路径可以构成一个封闭的形状
相当于画布上下文 context 的原生方法context.closePath
如果进行序列化,则对应于 SVG 的路径字符串的结束命令Z
或z
另外序列化器还有一个核心方法,用于将绘制方法转换/序列化为字符串
path.toString()
将序列化器(依次)设置的一系列方法(这些方法可直接在画布 canvas 上绘制出路径),转换为字符串形式,可用于 SVG 的元素<path>
的属性d
的属性值
Path2D
JS 原生提供了一个称为 Path2D
的类,它的实例化对象 new Path2D()
可以调用画布上下文 context 的一些方法,在画布上绘制路径
另外它还有一个功能,在实例化时支持传入 SVG 的路径字符串 new Path2D(pathString)
将其转换为画布的路径绘制方法,这和 path.toString()
的作用相反
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
//
let p = new Path2D("M10 10 h 80 v 80 h -80 Z");
ctx.fill(p); // 根据 SVG 的路径字符串,在画布中绘制出一个正方形