原文位址: https://www.jeremyjone.com/490/, 轉載請注明。
橢圓
通過前面的文章,我們已經可以繪制大部分圖形以及文字。但是,在
canvas
中,橢圓是一個複雜的存在,本身我們上學時學習橢圓本身也是一個複雜的結構。我看了很多畫橢圓的方案,大部分分為兩類:
- 第一類是 使用
畫一個圓形,然後将其縮放變形,完成一個橢圓。arc()
- 第二類是 使用貝塞爾曲線,即使用多條貝塞爾曲線混合拼接為一個橢圓。
經過我的實際測試,采用我認為比較簡單并且顯示效果比較好的方式,使用貝塞爾曲線的方式繪制橢圓。
剛才說過,貝塞爾的方式是使用多條曲線拼接,一個橢圓可以是兩條曲線、三條曲線,或四條甚至更多曲線拼接。我這裡使用兩條就夠了,而且很大程度減少我們的計算量。
關于貝塞爾曲線
貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用于二維圖形應用程式的數學曲線。
在
canvas
中,使用
bezierCurveTo()
方法來繪制貝塞爾曲線,該方法通過使用表示三次貝塞爾曲線的指定控制點,向目前路徑添加一個點。
- 提示:三次貝塞爾曲線需要三個點。前兩個點是用于三次貝塞爾計算中的控制點,第三個點是曲線的結束點。曲線的開始點是目前路徑中最後一個點。如果路徑不存在,那麼請使用 beginPath() 和 moveTo() 方法來定義開始點。

** 以上摘自HTML5 canvas bezierCurveTo()方法說明
通過貝塞爾曲線繪制橢圓
通過上圖,我們可以清楚看到繪制一條貝塞爾曲線的基本要素。
是以,我們的橢圓應該大緻如下(純滑鼠繪制,别吐~ ~ ~):
從圖中可以看到,橢圓可以被分成兩條貝塞爾曲線,我們隻需要找到對應的點即可。計算過程忽略,直接看代碼(代碼已經經過位置計算的優化,看上去更像使用滑鼠點選的起始點到結束點的橢圓):
let k = ((x2 - x1) / 0.55);
let w = (x2 - x1) / 2;
let h = (y2 - y1) / 2;
// bezier double ellipse algorithm
context.moveTo(x1, y1 + h);
context.bezierCurveTo(x1, y1 + h * 3, x1 + w * 11 / 5, y1 + h * 3, x1 + w * 11 / 5, y1 + h);
context.bezierCurveTo(x1 + w * 11 / 5, y1 - h, x1, y1 - h, x1, y1 + h);
context.stroke();
效果:
這樣就繪制出了一個比較完美的橢圓。
橡皮擦
在canvas中,有三個繪制圖形函數,分别是
fillRect()
、
strokeRect()
、
clearRect()
,分别是填充圖形,空心矩形,和清除矩形,前面兩個函數我們已經使用過。最後的函數通常:
clearRect(0, 0, canvas.width, canvas.height)
可以完成清屏的功能。
我們如果想要達到橡皮擦的功能,該如何操作呢?
其實原理是一樣的,隻不過,我們需要先固定住我們需要修改的圖檔。
context.arc(x1, y1, 10, 0, 2 * Math.PI); // 畫一個圓形,位置即滑鼠目前位置,大小就是橡皮擦的半徑大小,當然,也可以不适用圓形,任意形狀的橡皮擦都可以。
context.clip(); // 這句很重要,它可以将上面一句定義的形狀,從目前畫布中剪切出來單獨操作,如果沒有這一句,那麼一會操作的仍然是整幅畫布。
context.clearRect(0, 0, canvas.width, canvas.height); // 這句很簡單,和剛才的清空示例是一樣的。
self.X1 = self.X2;
self.Y1 = self.Y2;
是以,它的整體邏輯分三步:
定義橡皮擦的大小和形狀,通常我們定義為圓形。
固定畫闆,将橡皮擦的内容單獨剪切出來。
清空剪切出來的内容,就完成了橡皮功能。
是不是很簡單,當然,需要注意的是,随後不要忘記和随心畫一樣,實時修改傳入的坐标,達到連續擦出的效果。
這樣,簡單的橡皮功能也完成了。
完整的内容已經更新在了我的github - canvasPaint中,您也可以通過我的示例來測試一下功能。
前期目錄:
JavaScript 之 canvas(一)-- 認識canvas
JavaScript 之 canvas(二)-- 繪制基本圖形
JavaScript 之 canvas(三)-- 使用滑鼠實時繪制圖形
JavaScript 之 canvas(四)-- 繪制文字