画布包
Skia
现在提供了,在Web
上轻松部署图形API
的WebAssembly
构建,即CanvasKit
.
CanvasKit
提供了测试新的Canvas
和SVG
平台API
的地基,从而在Web
平台上,实现快节奏
开发.还可用作要求如Skia
的Lottie
动画支持等边角特征
的自定义Web
应用的部署机制
.
特征
1,按允许直接绘画到HTML
画布的SkSurface
封装的WebGL
环境
2,提供Skia
的canvas/paint/path/text
接口的核心集,见绑定
3,绘画
到硬件加速的后端
4,使用Skia
的模糊
安全测试
下载
在NPM
上取CanvasKit
这里.可在npm
包的types/
子目录中或Skia
仓库中找到文档
和ts
定义.
另见快速入门指南.
路径包.
Skia
已用WebAssembly
和asm.js
提供其SkPath
对象和许多相关
方法给JS
客户(如Web
浏览器).
特征
仍在快速开发PathKit
,因此确切API
可能会变化.
主要特点是:
1,API
兼容性(如直接替换)与2D
路径
2,可输出到SVG/Canvas/Path2D
3,公开各种路径特效.
示例代码
在npm
包中的example.html
,可查找如何使用PathKit
这里.
应用接口
该库的主要特征是SkPath
对象.可从如下创建:
1,从PathKit.FromSVGString(str)
路径的SVG
串
2,从动词和参数
的PathKit.FromCmds(cmds)
二维数组.
3,FromPathKit.NewPath()
(将为空)
4,现有带path.copy()
或PathKit.NewPath(path)
的SkPath
的副本
可导出为:
1,SVG
串:path.toSVGString()
2,Path2D
对象:path.toPath2D()
3,直接到2D
画布环境:path.toCanvas(ctx)
4,动词和参数的二维数组
:path.toCmds()
创建SkPath
对象后,可如下与之交互:
1,通过Path2D
操作(moveTo,lineTo,rect,arc
,等)
2,与使用op
或PathKit.MakeFromOp(p1,p2,op)
的其他路径
组合.
如,path1.op(path2,PathKit.PathOp.INTERSECT)
会设置path1
为path1
和path2
重叠(相交)所表示的区域
.
PathKit.MakeFromOp(path1,path2,PathKit.PathOp.INTERSECT)
将同样,但按新的SkPath
对象返回.
3,使用一些(修剪,破折号,描边
等)特效
调整.
重要提示:离开域
时,必须使用path.delete()
清理创建的(SkPath,SkOpBuilder
等)对象,以避免泄漏WASM
堆中的内存.
这包括构造器,copy()
或以"make"
为前缀
的函数.
路径包
cpp
FromSVGString(str)
str
:表示SVGPath
这里的串
返回一个动作和参数
与SVG
串相同的SkPath
,如果失败
,则返回null
.
例:
cpp
let path = PathKit.FromSVGString('M150 0 L75 200 L225 200 Z');
`path`表示一个`三角形`,出域时,记得执行`path.delete()`.
cpp
FromCmds(cmds)
cmds
为2D
命令数组的Array<Array<Number>>
,其中命令是一个动词加其参数
.
返回包含列表
中动作和参数
的SkPath
,如果失败,则返回null
.
比多次调用.moveTo()
,.lineTo()
等更快.
例:
cpp
let cmds = [
[PathKit.MOVE_VERB, 0, 10],
[PathKit.LINE_VERB, 30, 40],
[PathKit.QUAD_VERB, 20, 50, 45, 60],
];
let path = PathKit.FromCmds(cmds);
//`path`与用户完成路径相同
//let path = PathKit.NewPath().moveTo(0, 10).lineTo(30, 40).quadTo(20, 50, 45, 60);
//出域时,记得执行`path.delete()`
NewPath()
返回一个空的SkPath
对象.
例:
cpp
let path = PathKit.NewPath();
path.moveTo(0, 10)
.lineTo(30, 40)
.quadTo(20, 50, 45, 60);
//也可let path = new PathKit.SkPath();
(pathToCopy)
新路径
pathToCopy
:要复制的SkPath
路径.
返回在SkPath
中传递的副本的SkPath
.
例:
cpp
let otherPath = ...;
let clone = PathKit.NewPath(otherPath);
clone.simplify();
//也可let clone = new PathKit.SkPath(otherPath);
//或let clone = otherPath.copy();
cpp
MakeFromOp(pathOne, pathTwo, op)
1,pathOne
,SkPath
路径.
2,pathTwo
,SkPath
路径.
3,op
,PathOp
要应用的运算
返回一个给定的PathOp
应用至第一个和第二个路径
的结果(顺序很重要
)的新的SkPath
.
例:
cpp
let pathOne = PathKit.NewPath().moveTo(0, 20).lineTo(10, 10).lineTo(20, 20).close();
let pathTwo = PathKit.NewPath().moveTo(10, 20).lineTo(20, 10).lineTo(30, 20).close();
let mountains = PathKit.MakeFromOp(pathOne, pathTwo, PathKit.PathOp.UNION);
用户也可执行pathOne.op(pathTwo,PathKit.PathOp.UNION);
把生成
路径存储
到pathOne
中,来避免分配
另一个对象.
cpp
cubicYFromX(cpx1, cpy1, cpx2, cpy2, X)
cpx1,cpy1,cpx2,cpy2
:控制点的坐标
数字.
X
:要找相应Y坐标
的X坐标
数字.
快速求值三次缓入/缓出
曲线.按单位正方形
内的参数化立方曲线
定义.做出以下假设:
1,pt[0]
隐式{0,0}
2,pt[3]
隐式{1,1}
3,pts[1,2]
在单位
正方形内
返回给定X坐标
的Y坐标
.
cpp
cubicPtFromT(cpx1, cpy1, cpx2, cpy2, T)
cpx1,cpy1,cpx2,cpy2
控制点的坐标
数字.
T
数字,要查找相应(X,Y)
坐标的T参数
.
快速求值三次缓入/缓出
曲线.按单位正方形
内的参数化立方曲线
定义.做出以下假设:
1,pt[0]
隐式{0,0}
2,pt[3]
隐式{1,1}
3,pts[1,2]
在单位
正方形内
按长度
为2的数组
返回给定T值
的(X,Y)
坐标.
SkPath (object)
cpp
addPath(otherPath)
otherPath
,要附加
到此路径的SkPath
路径
把给定路径
添加到此路径
,然后返回此路径
来链接
.
addPath(otherPath, transform)
otherPath
,要追加
到此路径的SkPath
路径.
transform
,在追加它之前应用至otherPath
的SVGMatrix
转换在此.
在应用
转换后,把给定路径
添加到此路径
,然后返回此路径
以链接.细节,见Path2D.addPath()
这里.
cpp
addPath(otherPath, a, b, c, d, e, f)
otherPath
,要追加到此路径的SkPath
路径.
a,b,c,d,e,f
:数字,定义附加
转换前,应用至otherPath
转换的SVGMatrix
的六个组件
.
在应用
转换后,把给定路径
添加到此路径
,然后返回此路径
以链接.细节,见Path2D.addPath()
这里.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
let moreBoxes = PathKit.NewPath();
// 加未转换框(i.e. at 0, 0)
moreBoxes.addPath(box)
// 参数填充了一个类似如下2d矩阵:
// a c e
// b d f
// 0 0 1
//向右添加了300个点的框
.addPath(box, 1, 0, 0, 1, 300, 0)
//添加一个双向缩小50%的框.
.addPath(box, 0.5, 0, 0, 0.5, 0, 0);
//现在moreBoxes附加了3个路径
cpp
addPath(otherPath, scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2)
otherPath
,追加到此路径的SkPath
路径.
scaleX,skewX,transX,skewY,scaleY,transY,pers0,pers1,pers2
数字,仿射矩阵
的九个分量,用来定义,在附加前应用至otherPath
的变换
.
应用转换
后,把给定路径
添加到此路径,然后返回此路径
以链接.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
let moreBoxes = PathKit.NewPath();
moreBoxes.addPath(box)
// 加未转换框(i.e. at 0, 0)
// 参数填充了一个类似如下2d矩阵:
// a c e
// b d f
// 0 0 1
//向右添加了300个点的框
.addPath(box, 1, 0, 0,
0, 1, 300,
0, 0 ,1)
//添加一个双向缩小50%的框.
.addPath(box, 0.5, 0, 0,
0, 0.5, 0,
0, 0, 1)
//现在moreBoxes附加了3个路径
arc(x,y,radius,startAngle,endAngle,ccw=false)
x,y
:数字,圆弧中心
坐标.
radius
:数字,圆弧
半径.
startAngle,endAngle
:数字,角度
起点和终点,以弧度为单位,从正x轴
顺时针测量.
ccw
:布尔值,可选参数,指定是否应默认在起角
和尾角
之间用逆时针
而不是默认的顺时针绘画
弧.
把描述
的弧添加到此弧
中,然后返回此弧
以链接.细节,见Path2D.arc()
这里.
例:
cpp
let path = PathKit.NewPath();
path.moveTo(20, 120);
.arc(20, 120, 18, 0, 1.75 * Math.PI);
.lineTo(20, 120);
// 路径像一个去除了1/8切片的馅饼.
cpp
arcTo(x1, y1, x2, y2, radius)
x1,y1,x2,y2
数字,定义控制点
坐标.
radius
数字,圆弧
半径.
把描述
的弧添加到此弧
中,(如果需要,附加一行),然后返回此弧
以链接.细节Path2D.arcTo().
close()
或closePath()
返回笔
到当前子路径
开头,然后返回此值
以链接.细节,见Path2D.closePath()
这里.
computeTightBounds()
返回一个表示此路径最小和最大面积
的SkRect
.细节,见SkPath
参考.
cpp
conicTo(x1, y1, x2, y2, w)
x1,y1,x2,y2
:数字,定义控制点和终点
坐标.
w
:数字,圆锥的权重.
把描述的圆锥线
添加到此值
(如果需要,请附加一行),然后返回此行
以链接.细节,见SkPath参考.
复制()/copy()
返回此路径的副本.
cpp
cubicTo(cp1x, cp1y, cp2x, cp2y, x, y)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x,cp1y,cp2x,cp2y
数字,定义控制点
坐标.
x,y
数字,定义终点
坐标
把描述的立方线
添加到此值(如果需要,请附加一行),然后返回此值
以链接.细节,见Path2D.bezierCurveTo
这里.
cpp
dash(on, off, phase)
on,off
:数字,应打开(绘画
)和关闭(空白
)的破折号
的像素数.
phase
:数字,开/关
应偏移的像素数(模on+off)
对此应用虚线
路径特效,然后返回此值
以链接.有关视觉示例
,见上面的"Dash"
特效.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
box.dash(20, 10, 3);
//box现在是一个将绘画20像素然后停止10像素的`虚线矩形`.因为相位为3,因此`第一行`不会从(0,0)开始,而是从路径(3,0)周围的3个像素开始.
cpp
ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, ccw=false)
x,y
:数字,椭圆中心
坐标.
radiusX,radiusY
:数字,X和Y
方向半径
.
rotation:
数字,该椭圆的弧度旋转
.
startAngle,endAngle
:数字,要绘画
的起始角和结束角
,以正x轴
的弧度
为单位.
ccw
:布尔值
,指定是否应在起角
和尾角
之间逆时针
而不是默认的顺时针
绘画椭圆的可选参数
.
把描述椭圆
添加到此
,然后返回此椭圆
以链接.细节,见Path2D.ellipse
这里.
cpp
equals(otherPath)
otherPath
:要比较的SkPath
路径.
根据此路径
是否等于otherPath
返回布尔值
.
cpp
getBounds()
返回表示此路径的最小和最大面积
的SkRect
.细节,见SkPath
参考.
cpp
getFillType()
根据此路径
返回FillType
.默认为PathKit.FillType.WINDING
,但可能会随op()
或simplify()
更改.
客户一般需要getFillTypeString()
,因为可直接传递该值
给SVG
或Canvas
.
cpp
getFillTypeString()
返回一个表示此路径fillType
的String
.这些值为"nonzero"
或"evenodd"
.
例:
cpp
let path = ...;
let ctx = document.getElementById('canvas1').getContext('2d');
ctx.strokeStyle = 'green';
ctx.fill(path.toPath2D(), path.getFillTypeString());
cpp
moveTo(x, y)
x,y
:数字,笔应移动到的目标位置
坐标.
移动
笔(不绘画
)到给定坐标
,然后返回此坐标
以链接.细节,见Path2D.moveTo
这里.
cpp
lineTo(x, y)
x,y
:数字,笔应移动到的目标位置
坐标.
绘画
一条给定坐标
直线,然后返回此直线
以链接.细节,见Path2D.lineTo
这里.
op(otherPath,操作)
otherPath
:要与this
路径组合的另一条SkPath
路径.
operation
:应用至两个路径的PathOp
操作.
用给定操作与otherPath
合并到此路径
中,并返回此路径
以链接.
例:
cpp
let pathOne = PathKit.NewPath().moveTo(0, 20).lineTo(10, 10).lineTo(20, 20).close();
let pathTwo = PathKit.NewPath().moveTo(10, 20).lineTo(20, 10).lineTo(30, 20).close();
//组合两个三角形为两座山的样子
let mountains = pathOne.copy().op(pathOne, pathTwo, PathKit.PathOp.UNION);
//设置`pathOne`为`pathOne`和`pathTwo`重叠的小三角形
pathOne.op(pathOne, pathTwo, PathKit.PathOp.INTERSECT);
//既然调用了`copy()`,记得在山上调用`delete()`.
cpp
quadTo(cpx, cpy, x, y) or quadraticCurveTo(cpx, cpy, x, y)
cpx,cpy
:数字,控制点
坐标.
x,y
:数字,终点
坐标.
用给定坐标绘画
二次贝塞尔
曲线,然后返回此曲线
以链接.细节,见Path2D.quadraticCurveTo
这里.
cpp
rect(x, y, w, h)
x,y
:数字,矩形左上角
坐标.
w,h
:数字,矩形的宽高
在此基础上绘画
一个矩形,然后返回此矩形
以链接.细节,见Path2D.rect
这里.
cpp
setFillType(fillType)
fillType
:FillType
,新的fillType
.
设置路径的fillType
.细节,见SkPath
参考.
简化(simplify)()
设置此路径
为一组描述与原始路径
相同区域的不重叠的等值线
.有关视觉
示例,见上面的"简化"特效.
cpp
stroke(opts)
opts
:包含删除的StrokeOpts
选项.
用给定
的选项划出
此路径.可用来搞各种特效
.有关视觉示例,见上面的"描边","增长"和"收缩"
特效.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
//用宽度10和圆角描边路径
let rounded = box.copy().stroke({width: 10, join: PathKit.StrokeJoin.ROUND});
//增长特效,即在盒子周围扩展20像素
let grow = box.copy().stroke({width: 20}).op(box, PathKit.PathOp.DIFFERENCE);
//收缩特效,从原图像收缩,
let simplified = box.copy().simplify(); // sometimes required for complicated paths
//有时`复杂`路径需要它,
let shrink = box.copy().stroke({width: 15, cap: PathKit.StrokeCap.BUTT})
.op(simplified, PathKit.PathOp.REVERSE_DIFFERENCE);
//记得在每个副本上调用delete()!
cpp
toCanvas(ctx)
ctx
:要在其上绘画路径的Canvas2DContext
画布.
在传递的CanvasContext
上绘画此路径.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
let ctx = document.getElementById('canvas1').getContext('2d');
ctx.strokeStyle = 'green';
ctx.beginPath();
box.toCanvas(ctx);
ctx.stroke(); // 也可ctx.fill()
toCmds()
返回动作和参数
的二维数组
.细节,见PathKit.FromCmds()
.
cpp
toPath2D()
返回与此路径
相同操作的Path2D
对象.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
let ctx = document.getElementById('canvas1').getContext('2d');
ctx.strokeStyle = 'green';
ctx.stroke(box.toPath2D());
cpp
toSVGString()
返回表示基于此路径的SVGPath
的一个String
.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
let svg = document.getElementById('svg1');
let newPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
newPath.setAttribute('stroke', 'green');
newPath.setAttribute('fill', 'white');
newPath.setAttribute('d', box.toSVGString());
svg.appendChild(newPath);
cpp
transform(matr)
matrS
:kMatrix
,即仿射变换
矩阵的九个数字
中的Array<Number>
.
给this
应用指定的转换
,然后返回此值
以链接.
cpp
transform(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2)
scaleX,skewX,transX,skewY,scaleY,transY,pers0,pers1,pers2
:数字,仿射变换
矩阵的九个数字
.
给此值应用指定的转换
,然后返回此值
以链接.
例:
cpp
let path = PathKit.NewPath().rect(0, 0, 100, 100);
//放大路径5倍,
path.transform([5, 0, 0,
0, 5, 0,
0, 0, 1]);
//向右移动路径`75`像素.
path.transform(1, 0, 75,
0, 1, 0,
0, 0, 1);
cpp
trim(startT, stopT, isComplement=false)
startT,stopT
:数字,[0,1]
中,指示要绘画
的路径的开始和停止"百分比"
的值
isComplement
:布尔值,在startT
和stopT
之间的区域,是否应该绘画修剪部分
的补码.
设置此路径
为原始路径
的子集
,然后返回此路径
以链接.有关视觉示例,见上面的"修剪"
特效.
例:
cpp
let box = PathKit.NewPath().rect(0, 0, 100, 100);
box.trim(0.25, 1.0);
//`box`现在是像(已删除`顶部段`)`U`的3个段.
cpp
SkOpBuilder (object)
此对象
允许链接多个PathOps
在一起.用
cpp
let builder = new PathKit.SkOpBuilder();
创建一个;创建时,内部状态为"空路径
".记得在构建器
和resolve()
的结果上调用delete()
.
add(path,operation)
path
:要与给定规则组合的SkPath
路径.
operation
:应用至两个路径的PathOp
操作.
把路径和操作数
添加到生成器
.
make()
或resolve()
根据给定路径和操作数
创建并返回新的SkPath
.
返回路径
出域时,记得在返回
路径上调用.delete()
.
cpp
SkMatrix (struct)
SkMatrix
,在C++
结构和JS
数组之间转换.带一个九元素
一维数组,并转换它为3x3
的2D
仿射矩阵.
SkRect(struct)
SkRect
使用以下所有值均为Number
的键,在C++
结构和JS
对象之间转换:
fLeft
:左上角的x坐标
fTop
:左上角的y坐标
.
fRight
:右下角的x坐标
fBottom
:右下角的y坐标
StrokeOpts(struct)
StrokeOpts
使用以下键,在C++
结构和JS
对象之间转换:
width
,路径线宽数.默认值1
.
miter_limit
,数字,斜接限制.默认为4
,见SkPaint
参考.
join
,StrokeJoin
要使用的联接.默认值为PathKit.StrokeJoin.MITER
.
细节,见SkPaint
参考.
cap
,StrokeCap
要使用的帽.默认值为PathKit.StrokeCap.BUTT
.见SkPaint
参考.
cpp
PathOp (enum)
公开以下枚举值
.它们是通过其.value
属性区分的常量对象
.
cpp
PathKit.PathOp.DIFFERENCE
PathKit.PathOp.INTERSECT
PathKit.PathOp.REVERSE_DIFFERENCE
PathKit.PathOp.UNION
PathKit.PathOp.XOR
在PathKit.MakeFromOp()
和SkPath.op()
中使用它们.
cpp
FillType (enum)
公开以下枚举值
.它们是通过其.value
属性区分的常量对象
.
cpp
PathKit.FillType.WINDING (also known as nonzero)
PathKit.FillType.EVENODD
PathKit.FillType.INVERSE_WINDING
PathKit.FillType.INVERSE_EVENODD
由SkPath.getFillType()
和SkPath.setFillType()
使用它们,但一般客户需要SkPath.getFillTypeString()
.
cpp
StrokeJoin (enum)
公开以下枚举值
.它们是通过其.value
属性区分的常量对象
.
cpp
PathKit.StrokeJoin.MITER
PathKit.StrokeJoin.ROUND
PathKit.StrokeJoin.BEVEL
细节,见SkPaint
参考.
cpp
StrokeCap (enum)
公开以下枚举值
.它们是通过其.value
属性区分的常量对象
.
cpp
PathKit.StrokeCap.BUTT
PathKit.StrokeCap.ROUND
PathKit.StrokeCap.SQUARE
细节,见SkPaint
参考.
常数
公开以下常量:
cpp
PathKit.MOVE_VERB = 0
PathKit.LINE_VERB = 1
PathKit.QUAD_VERB = 2
PathKit.CONIC_VERB = 3
PathKit.CUBIC_VERB=4
PathKit.CLOSE_VERB=5
PathKit.FromCmds()
需要它.
仅测试的函数
PathKit.LTRBRect(left,top,right,bottom)
left
:SkRect
左上角的数字x坐标
.
top
:SkRect
左上角的数字y坐标
.
right
:数字,SkRect
右下角的x坐标
.
bottom
:数字,SkRect
右下角的y坐标
.
返回有给定参数
的SkRect
对象.
SkPath.dump()
打印控制台的动词
和参数
.仅在调度/测试
中可用.