It' 隨時為你提供協助,Canvas2D

Aaron Krajeski
Aaron Krajeski

在著色器、網格和濾鏡的世界中,Canvas2D 可能不會讓您感到興奮。但應該會!30% 至 40% 的網頁都有 <canvas> 元素,且所有畫布中有 98% 都使用 Canvas2D 轉譯內容。在汽車、冰箱和太空中,都會使用 Canvas2D。

不過,就目前最先進的 2D 繪圖技術而言,這個 API 確實有點落後。幸運的是,我們一直努力在 Canvas2D 中實作新功能,以便追上 CSS,並簡化人因設計和改善效能。

第 1 部分:跟上 CSS 供應商的做法

CSS 含有某些 Canvas2D 缺少的繪圖指令。我們透過新版 API 新增了幾項最受歡迎的功能:

圓角矩形

圓角矩形:網路、運算、甚至文明的基礎。

無論說什麼,圓角矩形都非常實用:無論是按鈕、即時通訊泡泡、縮圖、對話框,您都可以自行命名。您一向可以在 Canvas2D 中製作圓角矩形,只是畫面會顯得有些雜亂:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';

const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;

ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();

為了製作簡單的圓角矩形,必須完成以下所有步驟:

圓角矩形。

新的 API 有 roundRect() 方法。

ctx.roundRect(upper, left, width, height, borderRadius);

因此,上述指令可以完全替換為:

ctx.roundRect(10, 10, 200, 100, 20);

ctx.roundRect() 方法也會為 borderRadius 引數輸入陣列,最多可包含四個數字。這些半徑會以 CSS 相同的方式控制圓角矩形的四個角落。例如:

ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);

觀看示範影片,親自試試

圓錐漸層

瞭解線性漸層:

const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);

線性漸層。

放射漸層:

const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');

ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);

放射漸層。

不過,如果是漂亮的圓錐漸層效果呢?

const grad = ctx.createConicGradient(0, 100, 100);

grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');

ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);

圓錐漸層。

文字調節器

Canvas2D 的文字算繪功能落後許多。Chrome 已為 Canvas2D 文字算繪新增了幾個新屬性:

這些屬性都與 CSS 對應的屬性相符,且名稱相同。

第 2 部分:人體工學調整

過去,Canvas2D 的某些功能雖然可行,但實作方式過於複雜。以下是針對想要使用 Canvas2D 的 JavaScript 開發人員,提供一些提升使用體驗的改善項目:

重設背景資訊

為瞭解釋清理畫布,我編寫了一個簡單靈活的函式來繪製復古模式

draw90sPattern();

帶有復古三角形和正方形的圖案。

太好了!我剛好建立好這些圖案,接下來要清理畫布,並繪製其他內容。 等等,我們如何再次清理無框畫?太好了!ctx.clearRect(),當然可以。

ctx.clearRect(0, 0, canvas.width, canvas.height);

咦,這麼做沒用。對啊!我必須先重設轉換:

ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
空白畫布。

太棒了,空白畫布。接下來,我們來畫出漂亮的水平線:

ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();

水平線和對角線。

吼!答錯了!😡? 那這額外的工作是什麼?另外,為什麼它是粉紅色的?好的,我們來檢查 StackOverflow。

canvas.width = canvas.width;

為什麼這麼愚蠢?為什麼這會這麼困難?

但現在不必這麼麻煩了。有了新的 API,我們就能提供簡單、優雅、美觀的突破性功能:

ctx.reset();

抱歉,作業時間太長。

篩選器

SVG 濾鏡是獨立的元素,如果是第一次使用這項服務,強烈建議您閱讀 The Art Of SVG Filters And Why It Is Awesome,文中展示部分驚人潛力。

您現在可以為 Canvas2D 使用 SVG 樣式濾鏡了!您只需將篩選器設為指向網頁上其他 SVG 濾鏡元素的網址即可:

<svg>
  <defs>
    <filter id="svgFilter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
      <feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
      <feColorMatrix type="hueRotate" values="90" />
    </filter>
  </defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);

ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);

寫出了很棒的模式:

套用了模糊效果的懷舊圖案。

不過,如果您想執行上述操作,但不想在 JavaScript 中使用字串,該怎麼辦呢?有了新的 API,這完全可行。

ctx.filter = new CanvasFilter([
  { filter: 'gaussianBlur', stdDeviation: 5 },
  {
    filter: 'convolveMatrix',
    kernelMatrix: [
      [-3, 0, 0],
      [0, 0.5, 0],
      [0, 0, 3],
    ],
  },
  { filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);

簡單易懂!請到這裡試用並試用參數。

第 3 部分:效能提升

我們也希望透過新 Canvas2D API,盡可能提升效能。我們新增了多項功能,讓開發人員更精細地控管網站,盡可能提供最流暢的影格速率:

經常閱讀

使用 getImageData() 從畫布讀取像素資料。這可能會非常緩慢。這個新的 API 可讓您明確將畫布標示為要再次朗讀 (例如生成式效果)。這可讓您在背景最佳化作業,並快速擴充畫布,適合多種用途。這項功能在 Firefox 已有一段時間,並最後是 Canvas 規格的一部分。

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });

情境損失

讓悲傷的分頁再次快樂起來!如果用戶端的 GPU 記憶體用盡,或發生其他災難性事件,您現在可以接收回呼,並視需要重新繪製:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);

如要進一步瞭解畫布內容和損失,請參閱 WHATWG 維基上的詳細說明

結論

無論您是 Canvas2D 的新手、使用多年,還是多年未使用,我都建議您再看看畫布。這是一直存在的 API-next-door。