画矶包快速入门
CanvasKit
是用比canvasAPI
更高级功能集
的Skia
来绘画元素到canvas
中的wasm
模块.
最小应用
此例是个最小Canvaskit
应用,它为一帧
绘画一个圆角矩形
.从unpkg.com
中提取wasm
二进制文件,但你也可自己构建和管理
它.
<canvas id=foo width=300 height=300></canvas>
<script type="text/Js"src="https://unpkg.com/canvaskit-wasm@0.19.0/bin/canvaskit.js"></script>
<script type="text/Js">const ckLoaded = CanvasKitInit({locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.19.0/bin/'+file});ckLoaded.then((CanvasKit) => {const surface = CanvasKit.MakeCanvasSurface('foo');const paint = new CanvasKit.Paint();paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));paint.setStyle(CanvasKit.PaintStyle.Stroke);paint.setAntiAlias(true);const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);function draw(canvas) {canvas.clear(CanvasKit.WHITE);canvas.drawRRect(rr, paint);}surface.drawOnce(draw);});
</script>
分解为几个部分
来解释:
<canvas id=foo width=300 height=300></canvas>
创建CanvasKit
要绘画的画布
.该元素控制绘图缓冲
的宽度和高度
,css
风格控制绘画
到这些像素
后应用的缩放
.
尽管使用了canvas
元素,但CanvasKit
并没有调用HTML
的canvas
自己的绘画
方法.它使用此canvas
元素,来取WebGL2
环境,并用编译为WebAssembly
的C++
代码来绘图
,然后在每帧
结束时向GPU
发送命令.
<script type="text/Js"src="https://unpkg.com/canvaskit-wasm@0.19.0/bin/canvaskit.js"></script>
和
const ckLoaded = CanvasKitInit({locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.19.0/bin/'+file});
ckLoaded.then((CanvasKit) => {
分别加载canvaskit
助手js
和wasm
二进制文件.CanvasKitInit
接受一个一般叫CanvasKit
的a
函数函数,a
允许你更改
它试查找canvaskit.wasm
的路径,并返回一个用加载
模块解析
的promise
.
const surface = CanvasKit.MakeCanvasSurface('foo');
创建与上述HTMLcanvas
元素关联的Surface
.默认硬件加速
,但可调用MakeSWCanvasSurface
来覆盖.MakeCanvasSurface
也可指定替代
颜色空间或gl
属性.
const paint = new CanvasKit.Paint();
paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
paint.setStyle(CanvasKit.PaintStyle.Stroke);
paint.setAntiAlias(true);
const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);
创建
绘画,描述如何在canvaskit
中填充或描边
,矩形,路径,文本和其他几何图形
.rr
是一个在X轴
上圆角
半径为25
,在y轴
上圆角半径为15
个像素的圆角矩形
.
function draw(canvas) {canvas.clear(CanvasKit.WHITE);canvas.drawRRect(rr, paint);
}
定义绘画帧的函数
.它提供了一个在上面绘画的Canvas
对象.一个用来清理
整个画布,另一个用上面的画笔
绘画圆形矩形
.
还删除了画笔
对象.必须删除使用new
或以make
为前缀的方法创建的CanvasKit
对象,才能释放wasm
内存.Js
的GC
不会自动处理它.
rr
只是一个不是用new
创建的数组,也不指向WASM
内存,因此不必对它调用delete
.
surface.drawOnce(draw);
paint.delete()
给绘图
函数提交调用并刷新表面
的surface.drawOnce
.刷新后,Skia
处理并批发送WebGL
命令,这样,在屏幕
上出现可见
更改.
基本绘画循环
如果要在画布
上每一帧,都重画
该怎么办?此例像90
年代的屏幕保护
程序一样,反弹一个圆角矩形
.
ckLoaded.then((CanvasKit) => {const surface = CanvasKit.MakeCanvasSurface('foo2');const paint = new CanvasKit.Paint();paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));paint.setStyle(CanvasKit.PaintStyle.Stroke);paint.setAntiAlias(true);//`const rr=CanvasKit.RRectXY(CanvasKit.LTRBRect(10,60,210,260),25,15);`const w = 100; //矩形的大小const h = 60;let x = 10; //左上角的初始位置.let y = 60;let dirX = 1; //盒子总是在`四个对角线方向`之一上,按`恒定`速度移动let dirY = 1;function drawFrame(canvas) {//检查边界if (x < 0 || x+w > 300) {dirX *= -1; //撞击侧壁时反转X方向}if (y < 0 || y+h > 300) {dirY *= -1; //撞击顶壁和底壁时反转Y方向}//移动x += dirX;y += dirY;canvas.clear(CanvasKit.WHITE);const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, x+w, y+h), 25, 15);canvas.drawRRect(rr, paint);surface.requestAnimationFrame(drawFrame);}surface.requestAnimationFrame(drawFrame);
});
主要区别在,在绘画
每一帧前,定义
了一个要调用
的函数,并把它传递给surface.requestAnimationFrame(drawFrame);
,传递该回调
给画布,并刷新.
function drawFrame(canvas) {canvas.clear(CanvasKit.WHITE);//在此更新和绘画框架的代码surface.requestAnimationFrame(drawFrame);
}
surface.requestAnimationFrame(drawFrame);
创建函数
作为主绘图循环
.每次渲染
一帧(浏览器一般以60fps
为目标)时,都会调用
该函数,用白色清理
画布,重画
圆角矩形,然后调用surface.requestAnimationFrame(drawFrame)
来注册
要在下一帧
前再次调用
的函数.
surface.requestAnimationFrame(drawFrame)
把window.requestAnimationFrame
与surface.flush()``组合
在一起,并同样方法使用.
如果应用
仅因鼠标事件
而有可见
更改,请不要在drawFrame
函数末尾调用surface.requestAnimationFrame
.而仅在处理鼠标输入
后调用
它.
变形文本
CanvasKit
在HTMLCanvasAPI
上提供的最大功能之一是变形段落
.要用它,提供字体文件
,并在CanvasKit
和字体文件
都准备就绪时,使用Promise.all
运行代码.
const loadFont = fetch('https://storage.googleapis.com/skia-cdn/misc/Roboto-Regular.ttf').then((response) => response.arrayBuffer());
Promise.all([ckLoaded, loadFont]).then(([CanvasKit, robotoData]) => {const surface = CanvasKit.MakeCanvasSurface('foo3');const canvas = surface.getCanvas();canvas.clear(CanvasKit.Color4f(0.9, 0.9, 0.9, 1.0));const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);const paraStyle = new CanvasKit.ParagraphStyle({textStyle: {color: CanvasKit.BLACK,fontFamilies: ['Roboto'],fontSize: 28,},textAlign: CanvasKit.TextAlign.Left,});const text = 'Any sufficiently entrenched technology is indistinguishable from Js';const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);builder.addText(text);const paragraph = builder.build();paragraph.layout(290); //换行文本时使用的宽度(以像素为单位)canvas.drawParagraph(paragraph, 10, 10);surface.flush();
});
const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);
在CanvasKit
中,创建一个按名提供
的包含字体的各种文本工具
.如果需要,可在此语句
中加载
多个字体.
const paraStyle = new CanvasKit.ParagraphStyle({textStyle: {color: CanvasKit.BLACK,fontFamilies: ['Roboto'],fontSize: 28,},textAlign: CanvasKit.TextAlign.Left,
});
指定文本
风格及字体名,机器从字体管理器
中取它.可指定(color)
或(foregroundColor
和backgroundColor
)以获得高亮
.
有关API
的完整文档,请查看npm
包的types/
子目录或Skia
仓库中的ts
定义.
const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
builder.addText(text);
const paragraph = builder.build();
接着,用风格创建ParagraphBuilder
,添加
一些文本,并使用build()
完成它.或,可在段落
中使用多个TextStyles
.
const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
builder.addText(text1);
const boldTextStyle = CanvasKit.TextStyle({color: CanvasKit.BLACK,fontFamilies: ['Roboto'],fontSize: 28,fontStyle: {'weight': CanvasKit.FontWeight.Bold},
})
builder.pushStyle(boldTextStyle);
builder.addText(text2);
builder.pop();
builder.addText(text3);
const paragraph = builder.build();
最后,布局段落,即换行
文本到指定宽度
,然后用
paragraph.layout(290); //换行文本时使用的宽度(以像素为单位)
canvas.drawParagraph(paragraph, 10, 10); //段落左上角的(x,y)位置.
动画
Skia
现在为从AfterEffects
继承的Bodymovin
插件的JSON
动画提供了一个高性能,安全
的本地播放器.可在包括安卓
和iOS
的Skia
平台上使用.
该播放器
旨在在创建
当今广泛用来动画
的Lottie
播放器的基础上,为客户提高性能,功能集和平台凝聚力
.是Bodymovin
格式的忠实粉丝,并在可能时为Bodymovin/Lottie
贡献.
示例JSON
动画
Skia
的动画代码入口可在Googlesource
和GitHub
上找到.该代码是Skia
库的一部分,但也可作为单独的包提供这里及这里.
嵌入示例
1,可在此处找到用Skottie
原生播放器的示例C代码
.
2,可在此处找到取灵感的安卓
应用代码.
3,在此嵌入Skottie
到Viewer
应用中的示例代码
.
4,可按后面说明构建Viewer
或SkottieAndroid
应用.