Canvaskit快速入門教程
CanvasKit快速開始
CanvasKit 是一個 wasm 模塊,它使用 Skia 去繪制畫布元素,是一個比canvas API更高級的功能集。
一、最小應用
這個例子是一個最小的 Canvaskit 應用程序,它為一幀繪制一個圓角矩形。它從 unpkg.com 中提取 wasm 二進制文件,但您也可以自己構建和托管它。
<canvas id=foo width=300 height=300></canvas> <script type="text/javascript" src="https://unpkg.com/canvaskit-wasm@0.19.0/bin/canvaskit.js"></script> <script type="text/javascript"> 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>
創(chuàng)建 CanvasKit 將繪制到的畫布。這個元素是我們控制繪圖緩沖區(qū)的寬度和高度的地方,而它的 css 樣式將控制在繪制到這些像素后應用的任何縮放。盡管使用了畫布元素,CanvasKit 并沒有調用 HTML 畫布自己的繪制方法。它使用此畫布元素獲取 WebGL2 上下文并使用編譯為 WebAssembly 的 C++ 代碼執(zhí)行大部分繪圖工作,然后在每幀結束時向 GPU 發(fā)送命令。
<script type="text/javascript" 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});
加載canvaskit和wasm相關的二進制文件
CanvasKitInit接受一個函數(shù)參數(shù),允許您更改它將嘗試查找canvaskit.wasm的路徑,該函數(shù)的返回值是一個promise,解析為加載的模塊,通常將其命名為 CanvasKit。
const surface = CanvasKit.MakeCanvasSurface('foo');
創(chuàng)建一個與上面的 HTML canvas 元素關聯(lián)的 Surface。但可以通過調用 MakeSWCanvasSurface 來覆蓋。 MakeCanvasSurface 也是可以指定替代顏色空間或 gl 屬性的地方。這個Surface會硬件加速
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);
創(chuàng)建繪畫,描述如何在 canvaskit 中填充或描邊矩形、路徑、文本和其他幾何圖形。 rr 是一個圓角矩形,其角在 x 軸上的半徑為 25像素,在 y 軸上的半徑為 15 個像素。
function draw(canvas) { canvas.clear(CanvasKit.WHITE); canvas.drawRRect(rr, paint); }
定義一個函數(shù)來繪制。函數(shù)參數(shù)需要提供一個 Canvas 對象,我們可以在該對象上進行繪制調用。先清除畫布再繪制圓角矩形。
我們還刪除了 paint 對象。必須刪除使用 new 創(chuàng)建的 CanvasKit 對象或以 make 為前綴的方法才能釋放 wasm 內(nèi)存。 Javascript 的 GC 不會自動處理它。 rr 只是一個數(shù)組,不是用 new 創(chuàng)建的,也沒有指向任何 WASM 內(nèi)存,所以我們不必對其調用 delete。
surface.drawOnce(draw); paint.delete()
將繪圖函數(shù)交給 surface.drawOnce 進行調用并刷新表面。刷新后,Skia 將批處理并發(fā)送 WebGL 命令,使可見的變化出現(xiàn)在屏幕上。此示例繪制一次并處理表面,這就是一個一個canvaskit的最小應用程序。
三、基本繪制循環(huán)
如果我們需要每一幀都重繪到畫布上怎么辦?此示例像 90 年代的屏幕保護程序一樣彈跳圓角矩形。
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); const w = 100; // size of rect const h = 60; let x = 10; // initial position of top left corner. let y = 60; let dirX = 1; // box is always moving at a constant speed in one of the four diagonal directions let dirY = 1; function drawFrame(canvas) { // boundary check if (x < 0 || x+w > 300) { dirX *= -1; // reverse x direction when hitting side walls } if (y < 0 || y+h > 300) { dirY *= -1; // reverse y direction when hitting top and bottom walls } // move 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); });
這里的主要區(qū)別是我們定義了一個在繪制每一幀之前要調用的函數(shù),并將其傳遞給 surface.requestAnimationFrame(drawFrame);該回調被交給畫布并處理沖洗。
創(chuàng)建一個函數(shù)作為我們的主要繪圖循環(huán)。每次要渲染一幀(瀏覽器通常以 60fps 為目標)時,都會調用我們的函數(shù),我們用白色清除畫布,重新繪制圓形矩形,然后調用 surface.requestAnimationFrame(drawFrame) 注冊要再次調用的函數(shù)在下一幀之前。
surface.requestAnimationFrame(drawFrame) 結合了 window.requestAnimationFrame 和 surface.flush() 并且應該以相同的方式使用。如果您的應用程序只會因鼠標事件而做出可見更改,請不要在 drawFrame 函數(shù)末尾調用 surface.requestAnimationFrame。僅在處理鼠標輸入后調用它。
四、變形文本
CanvasKit 通過 HTML Canvas API 提供的最大功能之一是段落整形。要在您的應用程序中使用文本,請?zhí)峁┳煮w文件并在 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 Javascript'; const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); builder.addText(text); const paragraph = builder.build(); paragraph.layout(290); // width in pixels to use when wrapping text canvas.drawParagraph(paragraph, 10, 10); surface.flush(); });
const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);
創(chuàng)建一個對象,該對象按名稱為 CanvasKit 中的各種文本工具提供字體。如果需要,您可以在此語句中加載多種字體。
const paraStyle = new CanvasKit.ParagraphStyle({ textStyle: { color: CanvasKit.BLACK, fontFamilies: ['Roboto'], fontSize: 28, }, textAlign: CanvasKit.TextAlign.Left, });
指定文本的樣式。字體名稱 Roboto 將用于從字體管理器中獲取它。您可以指定 (color) 或 (foregroundColor and backgroundColor) 以突出顯示。有關 API 的完整文檔,請查看 npm 包的類型/子文件夾或 Skia 存儲庫中的 Typescript 定義。
const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); builder.addText(text); const paragraph = builder.build();
接下來,我們創(chuàng)建一個帶有樣式的 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); // width in pixels to use when wrapping text canvas.drawParagraph(paragraph, 10, 10); // (x, y) position of left top corner of paragraph.
以上就是Canvaskit快速入門教程的詳細內(nèi)容,更多關于Canvaskit入門教程的資料請關注腳本之家其它相關文章!
相關文章
JavaScript知識:構造函數(shù)也是函數(shù)
構造函數(shù)就是初始化一個實例對象,對象的prototype屬性是繼承一個實例對象。本文給大家分享javascript構造函數(shù)詳解,對js構造函數(shù)相關知識感興趣的朋友一起學習吧2021-08-08lodash內(nèi)部方法getData和setData實例解析
本篇章我們將了解lodash里內(nèi)部關于Data的操作方法,重點關注getData、setData兩個內(nèi)部方法,同時由實現(xiàn)上引申其他內(nèi)部封裝的方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08