首頁 > 軟體

Canvaskit快速入門教學

2023-03-17 06:05:22

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>

建立 CanvasKit 將繪製到的畫布。這個元素是我們控制繪圖緩衝區的寬度和高度的地方,而它的 css 樣式將控制在繪製到這些畫素後應用的任何縮放。儘管使用了畫布元素,CanvasKit 並沒有呼叫 HTML 畫布自己的繪製方法。它使用此畫布元素獲取 WebGL2 上下文並使用編譯為 WebAssembly 的 C++ 程式碼執行大部分繪圖工作,然後在每幀結束時向 GPU 傳送命令。

<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接受一個函數引數,允許您更改它將嘗試查詢canvaskit.wasm的路徑,該函數的返回值是一個promise,解析為載入的模組,通常將其命名為 CanvasKit。

const surface = CanvasKit.MakeCanvasSurface('foo');

建立一個與上面的 HTML canvas 元素關聯的 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);

建立繪畫,描述如何在 canvaskit 中填充或描邊矩形、路徑、文字和其他幾何圖形。 rr 是一個圓角矩形,其角在 x 軸上的半徑為 25畫素,在 y 軸上的半徑為 15 個畫素。

function draw(canvas) {
  canvas.clear(CanvasKit.WHITE);
  canvas.drawRRect(rr, paint);
}

定義一個函數來繪製。函數引數需要提供一個 Canvas 物件,我們可以在該物件上進行繪製呼叫。先清除畫布再繪製圓角矩形。

我們還刪除了 paint 物件。必須刪除使用 new 建立的 CanvasKit 物件或以 make 為字首的方法才能釋放 wasm 記憶體。 Javascript 的 GC 不會自動處理它。 rr 只是一個陣列,不是用 new 建立的,也沒有指向任何 WASM 記憶體,所以我們不必對其呼叫 delete。

surface.drawOnce(draw);
paint.delete()

將繪圖函數交給 surface.drawOnce 進行呼叫並重新整理表面。重新整理後,Skia 將批次處理並行送 WebGL 命令,使可見的變化出現在螢幕上。此範例繪製一次並處理表面,這就是一個一個canvaskit的最小應用程式。

codesandbox.io/s/suspiciou…

三、基本繪製迴圈

如果我們需要每一幀都重繪到畫布上怎麼辦?此範例像 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);
});

codesandbox.io/s/zen-bush-…

這裡的主要區別是我們定義了一個在繪製每一幀之前要呼叫的函數,並將其傳遞給 surface.requestAnimationFrame(drawFrame);該回撥被交給畫布並處理沖洗。

建立一個函數作為我們的主要繪圖迴圈。每次要渲染一幀(瀏覽器通常以 60fps 為目標)時,都會呼叫我們的函數,我們用白色清除畫布,重新繪製圓形矩形,然後呼叫 surface.requestAnimationFrame(drawFrame) 註冊要再次呼叫的函數在下一幀之前。

surface.requestAnimationFrame(drawFrame) 結合了 window.requestAnimationFrame 和 surface.flush() 並且應該以相同的方式使用。如果您的應用程式只會因滑鼠事件而做出可見更改,請不要在 drawFrame 函數末尾呼叫 surface.requestAnimationFrame。僅在處理滑鼠輸入後呼叫它。

四、變形文字

CanvasKit 通過 HTML Canvas API 提供的最大功能之一是段落整形。要在您的應用程式中使用文字,請提供字型檔案並在 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();
});

codesandbox.io/s/serene-ch…

const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);

建立一個物件,該物件按名稱為 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();

接下來,我們建立一個帶有樣式的 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快速入門教學的詳細內容,更多關於Canvaskit入門教學的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com