[JavaScript30 筆記] 08 - Fun with HTML5 Canvas

寫在系列開篇

在學(xué)習(xí)了基本的 HTML / CSS / JavaScript 之后沒有啥 side project 就直接開始學(xué) Angular 做項目。遇到最近很火的JavaScript30這個項目后決心好好實踐一下 Vanilla JavaScript。

對于每個挑戰(zhàn),我會自己在看過視頻了解原理后自己實現(xiàn)一遍并在 blog 里記錄過程、想法和相關(guān)資料。源碼放在我的 Github上,demo 通過 Github Pages 部署,點擊這里或 Github 的 readme 中連接可以訪問。

Objective

實現(xiàn)一個簡單的彩虹效果的 Canvas 畫筆。

demo
demo

Steps

  1. 獲取 canvas 以及其 context 并設(shè)置初始屬性;
  2. 設(shè)置需要的4個事件(mouseup, mousedown, mouseout, mousemove)的監(jiān)聽器;
  3. 在畫圖函數(shù)中設(shè)置 context 的狀態(tài)并完成畫圖。

Details and Things learned

<canvas> 可以完成圖像的繪制,功能十分強大。MDN 有非常好的教程,今天這個小 demo 只使用了 <canvas> 的線段繪制的一部分 API。

Prepare

首先要獲取元素以及 context:

const canvas = document.querySelector('#draw');
const ctx = canvas.getContext('2d');

這里我們只需要 2d 的繪制功能,如果需要繪制 3d 圖形,可以 getContext('webgl')。

然后設(shè)置幾個屬性:

  • ctx.strokeStyle = 'hsl(50, 100%, 50%)'; strokeStyle 可以設(shè)置 color, gradient, pattern
  • ctx.lineJoin = 'round'; 指定畫出的線段如何相交,提供了三種選項
    lineJoin
    lineJoin
  • ctx.lineCap = 'round'; 指定畫出的線段端點如何截止,同樣三種我們選擇 round
    lineCap
    lineCap
  • ctx.lineWidth = 10; 畫線段的寬度,in space units。

程序相關(guān)的

  • let isDrawing = false; 用于標明是否處于繪圖狀態(tài),在鼠標按下松開移出繪圖區(qū)時更新。
  • let lastX, lastY; 記錄每次移動鼠標前點的位置,從而可以畫出光滑曲線。
  • let hue = 0; 使用 hsl 來表征顏色,從而可以得到連續(xù)的顏色變化。
  • let widthGrow = true; 用來讓寬度來回變大變小。

畫圖過程

canvas 可以畫出多種圖形以及 animation 等特效,最簡單的畫路徑根據(jù) MDN 教程 分為以下幾步:

  • beginPath() - 清空context的所有狀態(tài)開始新的畫圖過程。
  • Path methods - 操作畫圖的點的移動,包括 moveTo(), lineTo(), bezierCurveTo(), quadraticCurveTo()等等。
  • closePath() - 結(jié)束 path 的規(guī)劃,之后的指令重新對 context 起作用。
  • stroke() - 畫!
  • fill() - 填充,這次沒用到。
    加入顏色,寬度調(diào)整后的完整代碼:
canvas.addEventListener('mousemove', (e) => {
  if (!isDrawing) return false;
  ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`; 
  ctx.beginPath();
  ctx.moveTo(lastX, lastY);
  ctx.lineTo(e.offsetX, e.offsetY);
  ctx.closePath();
  ctx.stroke();
  [lastX, lastY] = [e.offsetX, e.offsetY];
  hue = (hue + 1) % 360;
  if (ctx.lineWidth == 66 || ctx.lineWidth == 1) {
    widthGrow = !widthGrow;
  }
  ctx.lineWidth = ctx.lineWidth + (widthGrow ? 1 : -1);
})

Notice

如果不使用 [lastX, lastY] = [e.offsetX, e.offsetY];,每次畫圖的線似乎斷斷續(xù)續(xù)的,原因是每次只畫一個點,而不是一段線。

HSL

以前只會 RGBA 顏色表示,實際上 "Hue-saturation-lightness model (HSL)" 表示方法更為直觀,hue 是 0 - 360 的數(shù)字,然后選擇飽和度和亮度,可以方便的猜測出結(jié)果的顏色。這個網(wǎng)站可以方便預(yù)覽選取的顏色。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容